<!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