Showing posts with label AngularJs. Show all posts
Showing posts with label AngularJs. Show all posts

Jan 15, 2017

Apply Mixin Pattern for AngularJs applications

We love single page applications with AngularJs. We always aim to create high performance apps with beautiful source code. A developer needs to write readable and maintainable code. Some features to evaluate: class hierarchies, directory hierarchies, design patterns.

Example of good directory hierarchy:

We never desire a file with too much lines. On our projects, a source file does not exceed 600 lines. We always split a large file into many small files. This habit is good to write maintainable code. A technique used to split file is applying the Mixin pattern.

The $controller service is responsible for instantiating controllers, so we use it to create the "inheritance" with angular.extend(). Every our Angular controllers initialize the authentication controller (named AuthController) as required. Every line of the the authentication controller embed to run first. We think this is a good design pattern.


var AuthController = function($auth, $scope, $http, $warning, $state, $stateParams) {
    $scope.isAuthenticated = function() {
        return $auth.isAuthenticated();
    };

    $scope.logout = function() {
        if (!$auth.isAuthenticated());
        $auth.logout();
    };

    $scope.login = function() {
        var credentials = {
            email: $scope.email,
            password: $scope.password
        };

        $auth
            .login(credentials)
            .then(function(res) {
                $auth.setToken(res);
                var loginModal = angular.element('#m_login');
                if (loginModal.hasClass('in')) {
                    loginModal.modal('toggle');
                }
                if ($stateParams.next) {
                    // logged in, redirect to next state
                    $state.go($stateParams.next.name);
                }
            })
            .catch(function(res) {
                $warning(res);
            });
    };
}

And other controllers extend from the authentication controller. For example:

var EntryCollection = function($scope, $http, $controller, $rootScope, $warning) {
    angular.extend(this, $controller('AuthController', {$scope: $scope}));
    angular.extend(this, $controller('TagCollection', {$scope: $scope}));

    $scope.page_current = 1;
    $scope.paginate = function(page_index) {
        $http({
            url: 'api/entry?page=' + page_index,
            method: 'GET'
        }).then(function(res) {
            $scope.entries = res.data.data;
            $scope.page_last = res.data.last_page;
            // save current page
            $scope.page_current = page_index;
        }, function(res) {
            $warning(res);
        });
    };
    // start paginating
    $scope.paginate($scope.page_current);
};

Oct 15, 2016

Use free News API from newsapi.org with Angularjs

I tried to use news api provided by newsapi.org.
News API is a simple and easy-to-use API that returns JSON metadata for the headlines currently published on a range of news sources and blogs (see their sources here).Up to present their News API can provide live headlines from 66 sources.
Because they support COR so we can make requests directly from the front-end!
We get lastest articles from random source.
// app.js
var app = angular.module("app", ['ngSanitize']);

app.controller("scrapper", function($scope, $http, $q, $timeout) {
    var newsapi_org_apiKey = [
        // newsapi.org API key, you need to sign up for getting your key
        // or you can use API key used for examples in their API docs
        "1bef2b9f1a834a4ba7c821a4f7037c6a",
    ];

    // return promise
    var $getSources = function() {
        return $http.get('https://newsapi.org/v1/sources?language=en');
    };

    var $getArticles = function(source) {
        var deferred = $q.defer();
        $http
            .get('https://newsapi.org/v1/articles?source=' + source + '&sortBy=latest&apiKey=' + newsapi_org_apiKey[0])
            .success(function(data) {
                console.log('get articles successfully');
                deferred.resolve({
                    articles: data.articles
                });
            })
            .error(function(msg, code) {
                deferred.reject(msg);
            });
        return deferred.promise;
    };

    $getSources().then(function(payload) {
        // step 1: retrieve array of source successfully
        $scope.array_of_sources = _.map(payload.data.sources, function(item) {
            return item.id;
        });

        // step 2: get articles from the sources
        // count_attempt counts the number of tries, we initialize it 0
        // the number of tries can't be bigger than array_of_sources' length
        var count_attempt = 0;

        function _try() {
            count_attempt += 1;

            // source assigned randomly from approximately 66 sources
            var source = $scope.array_of_sources[_.random(0, $scope.array_of_sources.length - 1)];

            // get articles from the source
            $getArticles(source).then(function(data) {
                // assign to $scope.articles if success
                $timeout(function() {
                    $scope.articles = data.articles;
                }, 1);

            }, function() {
                // remove source from array_of_sources if on failure
                $scope.array_of_sources = _.reject($scope.array_of_sources, function(item) {
                    return item == source;
                });

                // if total tries is in limit, try another source from array_of_sources
                if (count_attempt < $scope.array_of_sources.length) {
                    _try();
                }
            });
        }
        _try();
    });
});
<html> <head> <meta charset="utf8"> </head> <body> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-sanitize/1.5.8/angular-sanitize.min.js"></script> <div ng-app="app" ng-controller="scrapper" class="our-content"> <div class="container" style="padding-top:30px;"> <div class="row"> <div class="col-xs-12 col-lg-8 col-lg-offset-2"> <ul class="list-group" style="border:none;"> <li ng-repeat="article in articles" class="list-group-item" style="border:none;"> <div class="panel panel-info" style="border:none;"> <div class="panel-heading" style="font-size:1.3em;"><a href="{{ article.url }}"><span ng-bind-html="article.title"></span></a></div> <div class="panel-body"> <span ng-bind-html="article.description"></span> <a class="btn btn-sm btn-info" href="{{ article.url}}">More</a> </div> </div> </li> </ul> </div> </div> </div> </div> <script src="app.js"></script> </body> </html>