A simple comment app usgin AngularJS
A Pen by César Mejía on CodePen.
A simple comment app usgin AngularJS
A Pen by César Mejía on CodePen.
<div class="comments-app" ng-app="commentsApp" ng-controller="CommentsController as cmntCtrl"> | |
<h1>Comments App - AngularJS</h1> | |
<!-- From --> | |
<div class="comment-form"> | |
<!-- Comment Avatar --> | |
<div class="comment-avatar"> | |
<img src="http://lorempixel.com/200/200/people"> | |
</div> | |
<form class="form" name="form" ng-submit="form.$valid && cmntCtrl.addComment()" novalidate> | |
<div class="form-row"> | |
<textarea | |
class="input" | |
ng-model="cmntCtrl.comment.text" | |
placeholder="Add comment..." | |
required></textarea> | |
</div> | |
<div class="form-row"> | |
<input | |
class="input" | |
ng-class="{ disabled: cmntCtrl.comment.anonymous }" | |
ng-disabled="cmntCtrl.comment.anonymous" | |
ng-model="cmntCtrl.comment.author" | |
ng-required="!cmntCtrl.comment.anonymous" | |
placeholder="Email" | |
type="email"> | |
</div> | |
<div class="form-row text-right"> | |
<input | |
id="comment-anonymous" | |
ng-change="cmntCtrl.anonymousChanged()" | |
ng-model="cmntCtrl.comment.anonymous" | |
type="checkbox"> | |
<label for="comment-anonymous">Anonymous</label> | |
</div> | |
<div class="form-row"> | |
<input type="submit" value="Add Comment"> | |
</div> | |
</form> | |
</div> | |
<!-- Comments List --> | |
<div class="comments"> | |
<!-- Comment --> | |
<div class="comment" ng-repeat="comment in cmntCtrl.comments | orderBy: '-date'"> | |
<!-- Comment Avatar --> | |
<div class="comment-avatar"> | |
<img ng-src="{{ comment.avatarSrc }}"> | |
</div> | |
<!-- Comment Box --> | |
<div class="comment-box"> | |
<div class="comment-text">{{ comment.text }}</div> | |
<div class="comment-footer"> | |
<div class="comment-info"> | |
<span class="comment-author"> | |
<em ng-if="comment.anonymous">Anonymous</em> | |
<a ng-if="!comment.anonymous" href="{{ comment.author }}">{{ comment.author }}</a> | |
</span> | |
<span class="comment-date">{{ comment.date | date: 'medium' }}</span> | |
</div> | |
<div class="comment-actions"> | |
<a href="#">Reply</a> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Comment - Dummy --> | |
<div class="comment"> | |
<!-- Comment Avatar --> | |
<div class="comment-avatar"> | |
<img src="http://gravatar.com/avatar/412c0b0ec99008245d902e6ed0b264ee?s=80"> | |
</div> | |
<!-- Comment Box --> | |
<div class="comment-box"> | |
<div class="comment-text">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iusto temporibus iste nostrum dolorem natus recusandae incidunt voluptatum.</div> | |
<div class="comment-footer"> | |
<div class="comment-info"> | |
<span class="comment-author"> | |
<a href="mailto:[email protected]">Sexar</a> | |
</span> | |
<span class="comment-date">Feb 2, 2013 11:32:04 PM</span> | |
</div> | |
<div class="comment-actions"> | |
<a href="#">Reply</a> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Comment - Dummy --> | |
<div class="comment"> | |
<!-- Comment Avatar --> | |
<div class="comment-avatar"> | |
<img src="http://lorempixel.com/200/200/people"> | |
</div> | |
<!-- Comment Box --> | |
<div class="comment-box"> | |
<div class="comment-text">Eligendi voluptatum ducimus architecto tempore, quaerat explicabo veniam fuga corporis totam reprehenderit quasi sapiente modi tempora at perspiciatis mollitia, dolores voluptate. Cumque, corrupti?</div> | |
<div class="comment-footer"> | |
<div class="comment-info"> | |
<span class="comment-author"> | |
<a href="mailto:[email protected]">Ximme</a> | |
</span> | |
<span class="comment-date">Jan 31, 1986 11:32:04 PM</span> | |
</div> | |
<div class="comment-actions"> | |
<a href="#">Reply</a> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> |
(function(){ | |
'use strict'; | |
angular | |
.module('commentsApp', []) | |
.controller('CommentsController', CommentsController); | |
// Inject $scope dependency. | |
CommentsController.$inject = ['$scope']; | |
// Declare CommentsController. | |
function CommentsController($scope) { | |
var vm = this; | |
// Current comment. | |
vm.comment = {}; | |
// Array where comments will be. | |
vm.comments = []; | |
// Fires when form is submited. | |
vm.addComment = function() { | |
// Fixed img. | |
vm.comment.avatarSrc = 'http://lorempixel.com/200/200/people/'; | |
// Add current date to the comment. | |
vm.comment.date = Date.now(); | |
vm.comments.push( vm.comment ); | |
vm.comment = {}; | |
// Reset clases of the form after submit. | |
$scope.form.$setPristine(); | |
} | |
// Fires when the comment change the anonymous state. | |
vm.anonymousChanged = function(){ | |
if(vm.comment.anonymous) | |
vm.comment.author = ""; | |
} | |
} | |
})(); |
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.14/angular.min.js"></script> |
* { | |
box-sizing: border-box; | |
margin: 0; | |
padding: 0; | |
-webkit-box-sizing: border-box; | |
-moz-box-sizing: border-box; | |
} | |
body{ | |
background-color: #dee1e3; | |
font-family: "Roboto", "Tahoma", "Arial", sans-serif;, | |
} | |
.text-right{ text-align: right; } | |
.comments-app{ | |
margin: 50px auto; | |
max-width: 680px; | |
padding: 0 50px; | |
width: 100%; | |
} | |
.comments-app h1{ | |
color: #191919; | |
margin-bottom: 1.5em; | |
text-align: center; | |
text-shadow: 0 0 2px rgba(152, 152, 152, 1); | |
} | |
.comment-form{ } | |
.comment-form .comment-avatar{ } | |
.comment-form .form{ margin-left: 100px; } | |
.comment-form .form .form-row{ margin-bottom: 10px; } | |
.comment-form .form .form-row:last-child{ margin-bottom: 0; } | |
.comment-form .form .input{ | |
background-color: #fcfcfc; | |
border: none; | |
border-radius: 4px; | |
box-shadow: 0 1px 1px rgba(0, 0, 0, .15); | |
color: #555f77; | |
font-family: inherit; | |
font-size: 14px; | |
padding: 5px 10px; | |
outline: none; | |
width: 100%; | |
-webkit-transition: 350ms box-shadow; | |
-moz-transition: 350ms box-shadow; | |
-ms-transition: 350ms box-shadow; | |
-o-transition: 350ms box-shadow; | |
transition: 350ms box-shadow; | |
} | |
.comment-form .form textarea.input{ | |
height: 100px; | |
padding: 15px; | |
} | |
.comment-form .form label{ | |
color: #555f77; | |
font-family: inherit; | |
font-size: 14px; | |
} | |
.comment-form .form input[type=submit]{ | |
background-color: #555f77; | |
border: none; | |
border-radius: 4px; | |
box-shadow: 0 1px 1px rgba(0, 0, 0, .15); | |
color: #fff; | |
cursor: pointer; | |
display: block; | |
margin-left: auto; | |
outline: none; | |
padding: 6px 15px; | |
-webkit-transition: 350ms box-shadow; | |
-moz-transition: 350ms box-shadow; | |
-ms-transition: 350ms box-shadow; | |
-o-transition: 350ms box-shadow; | |
transition: 350ms box-shadow; | |
} | |
.comment-form .form .input:focus, | |
.comment-form .form input[type=submit]:focus, | |
.comment-form .form input[type=submit]:hover{ | |
box-shadow: 0 2px 6px rgba(121, 137, 148, .55); | |
} | |
.comment-form .form.ng-submitted .input.ng-invalid, | |
.comment-form .form .input.ng-dirty.ng-invalid{ | |
box-shadow: 0 2px 6px rgba(212, 47, 47, .55) !important; | |
} | |
.comment-form .form .input.disabled { | |
background-color: #E8E8E8; | |
} | |
.comments{ } | |
.comment-form, | |
.comment{ | |
margin-bottom: 20px; | |
position: relative; | |
z-index: 0; | |
} | |
.comment-form .comment-avatar, | |
.comment .comment-avatar{ | |
border: 2px solid #fff; | |
border-radius: 50%; | |
box-shadow: 0 1px 2px rgba(0, 0, 0, .2); | |
height: 80px; | |
left: 0; | |
overflow: hidden; | |
position: absolute; | |
top: 0; | |
width: 80px; | |
} | |
.comment-form .comment-avatar img, | |
.comment .comment-avatar img{ | |
display: block; | |
height: auto; | |
width: 100%; | |
} | |
.comment .comment-box{ | |
background-color: #fcfcfc; | |
border-radius: 4px; | |
box-shadow: 0 1px 1px rgba(0, 0, 0, .15); | |
margin-left: 100px; | |
min-height: 60px; | |
position: relative; | |
padding: 15px; | |
} | |
.comment .comment-box:before, | |
.comment .comment-box:after{ | |
border-width: 10px 10px 10px 0; | |
border-style: solid; | |
border-color: transparent #FCFCFC; | |
content: ""; | |
left: -10px; | |
position: absolute; | |
top: 20px; | |
} | |
.comment .comment-box:before{ | |
border-color: transparent rgba(0, 0, 0, .05); | |
top: 22px; | |
} | |
.comment .comment-text{ | |
color: #555f77; | |
font-size: 15px; | |
margin-bottom: 25px; | |
} | |
.comment .comment-footer{ | |
color: #acb4c2; | |
font-size: 13px; | |
} | |
.comment .comment-footer:after{ | |
content: ""; | |
display: table; | |
clear: both; | |
} | |
.comment .comment-footer a{ | |
color: #acb4c2; | |
text-decoration: none; | |
-webkit-transition: 350ms color; | |
-moz-transition: 350ms color; | |
-ms-transition: 350ms color; | |
-o-transition: 350ms color; | |
transition: 350ms color; | |
} | |
.comment .comment-footer a:hover{ | |
color: #555f77; | |
text-decoration: underline; | |
} | |
.comment .comment-info{ | |
float: left; | |
width: 85%; | |
} | |
.comment .comment-author{ } | |
.comment .comment-date{ } | |
.comment .comment-date:before{ | |
content: "|"; | |
margin: 0 10px; | |
} | |
.comment-actions{ | |
float: left; | |
text-align: right; | |
width: 15%; | |
} |