<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Full Stack Programming Challenge</title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<script src="index.js"></script>
<style>
.row {
border-bottom: 1px #ccc dashed;
padding: 10px 0;
}
.hglt {
background-color: yellow;
}
</style>
</head>
<body class="container wrapper">
<h1 class="text-center">Full Stack Programming Challenge</h1>
<i>
Features
<ul>
<li>Simple, efficient, and performant app in AngularJS 1.6 </li>
<li>App uses components only </li>
<li>App is built using Bootstrap </li>
<li>App is responsive </li>
<li>Loading indication </li>
<li>Live search bar </li>
<li>Search query highlighted </li>
</ul>
</i>
<div ng-app="postApp">
<post-list></post-list>
</div>
</body>
</html>
(function (angular) {
'use strict';
angular
.module('postApp', [])
.filter('highlight', function() {
return function(text, phrase) {
return phrase
? text.replace(new RegExp('('+phrase+')', 'gi'), '<b class="hglt">$1</b>')
: text;
};
})
.filter('trustHtml', [
'$sce',
function($sce) {
return function(value) {
return $sce.trustAs('html', value);
};
}
])
.factory('postFactory', ['$http',
function ($http) {
return {
getPosts: function () {
return $http.get('https://jsonplaceholder.typicode.com/posts');
},
getUsers: function () {
return $http.get('https://jsonplaceholder.typicode.com/users');
}
};
}])
.component('postList', {
templateUrl: 'postList.html',
controller: ['$scope', 'postFactory',
function ($scope, postFactory) {
var self = this;
self.state = 0;
self.handleSearch = function ($event) {
self.query = $event.value;
};
postFactory.getPosts().then(function (response) {
self.posts = response.data;
postFactory.getUsers().then(function (response) {
self.users = response.data;
self.usersMap = {};
var item, j, k, user;
for (j in self.users) {
item = self.users[j];
self.usersMap[item.id] = item;
}
for (k in self.posts) {
item = self.posts[k];
user = self.usersMap[item.userId];
item.name = user.name;
item.email = user.email;
}
self.state = 1;
}, function (response, status) {
self.state = 2;
});
}, function (response, status) {
self.state = 2;
});
}
]
})
.component('postDetail', {
templateUrl: 'postDetail.html',
bindings: {
post: '<',
query: '<'
}
})
.component('searchBar' , {
templateUrl: 'searchBar.html',
bindings: {
onSubmit: '&'
},
controller: ['$scope',
function ($scope) {
var self = this;
self.onChange = function(){
self.onSubmit({
$event: {
value: $scope.query
}
});
};
}
]
});
})(window.angular);
<div class="row">
<div class="col-sm-6">
<strong>Name:</strong> <span ng-bind-html="$ctrl.post.name | highlight:$ctrl.query | trustHtml"></span>
</div>
<div class="col-sm-6">
<strong>Email:</strong> <span ng-bind-html="$ctrl.post.email | highlight:$ctrl.query | trustHtml"></span>
</div>
<div class="col-sm-12">
<strong>Title:</strong> <span ng-bind-html="$ctrl.post.title | highlight:$ctrl.query | trustHtml"></span>
</div>
<div class="col-sm-12">
<strong>Body:</strong> <span ng-bind-html="$ctrl.post.body | highlight:$ctrl.query | trustHtml"></span>
</div>
</div>
<search-bar on-submit="$ctrl.handleSearch($event)"></search-bar>
<h2>Posts List</h2>
<div ng-show="$ctrl.state===0">Loading...</div>
<div ng-show="$ctrl.state===2">Error</div>
<post-detail ng-repeat="post in $ctrl.posts | filter:$ctrl.query" post="post" query="$ctrl.query"></post-detail>
<input type="text" class="form-control" placeholder="Search Posts..." ng-model="query" ng-change="$ctrl.onChange()">
# angular-list
Features
* Simple, efficient, and performant app in AngularJS 1.6
* App uses components only
* App is built using Bootstrap
* App is responsive
* Loading indication
* Live search bar
* Search query highlighted
Live demo
* https://plnkr.co/edit/aVwVYad5KKQyrDSXdSKS?p=preview