How to use filters within controllers in AngularJs (mini-challenge 12)

filters within controllers

Filters within controllers (mini-challenges 12)

AngularJs Mini-Challenges is a growing collection of “Challenges” about the most quirky parts of the AngularJs framework. It encourage you to find and fix common mistakes and subtle bugs, as well as performance issues and bad practices, that non-expert AngularJs programmers may encounter on their endeavours into the depths of the framework.

AngularJs Mini-Challenges does not aim to teach you AngularJs. Former knowledge of the Framework is strongly recommended in order to understand the topics covered in this Challenges. In order to learn the basics of the Framework, please head over to this excellent book:

 

book

Book Tip

ng-book – The Complete Book on AngularJS
Ready to master AngularJS? What if you could master the entire framework – with solid foundations – in less time without beating your head against a wall?


Amazon

 

The Challenge:

How would you use filters within controllers like “filter” in JavaScript? And how to create a custom filter?
For example in the html you can use filter’s filter to do a search in a list of elements:

 <tr ng-repeat="friend in friends | filter:searchText">

<table id="searchTextResults">
<tr>
<th>Name</th>
<th>Phone</th>
</tr>

<tr ng-repeat="friend in friends | filter:searchText">
<td>{{friend.name}}</td>
<td>{{friend.phone}}</td>
</tr>
</table>

 
 

Solution:

In AngularJs you can inject the $filter service within the controller, and use it with the following syntax for “filter”:

$filter('filter')(array, expression, comparator, anyPropertyKey)

 

function myController($scope, $filter)
{
   $scope.result = $filter('filter')($scope.arrayOfObjects, $scope.searchCriteria);
}

You can also use other AngularJs filters Build-in like:

 $scope.formatedDate = $filter('date')($scope.date, "yyyy-MM-dd");
 $scope.result = $filter('lowercase')($scope.name);

You can find here a list of build-in AngularJs filters:
https://docs.angularjs.org/api/ng/filter

 
 
Filter Example with pipe in the HTML:

 
 
Filter example within the controller using Javascript:

 
 

How to create custom filters in AngularJs

AngulrJs have a build-in method to register custom filters, using the same approach you can use when you register a controller, a service and factories. See following example:

var myApp = angular.module('myApp', []);
app.filter('myFilter', function() {
  return function(input, option1, option2) {
    var output;
    // Logic to make your filter works.
    return output;
  }
});

 
for more reference about how to create a custom filter you can refer to https://scotch.io/tutorials/building-custom-angularjs-filters
 

Prevent angular executing controller twice (Mini-Challenge 11)

Prevent angular executing controller twice (Mini-Challenge 11)

Prevent angular executing controller twice

AngularJs Mini-Challenges is a growing collection of “Challenges” about the most quirky parts of the AngularJs framework. It encourage you to find and fix common mistakes and subtle bugs, as well as performance issues and bad practices, that non-expert AngularJs programmers may encounter on their endeavours into the depths of the framework.

AngularJs Mini-Challenges does not aim to teach you AngularJs. Former knowledge of the Framework is strongly recommended in order to understand the topics covered in this Challenges. In order to learn the basics of the Framework, please head over to this excellent book:

 

book

Book Tip

ng-book – The Complete Book on AngularJS
Ready to master AngularJS? What if you could master the entire framework – with solid foundations – in less time without beating your head against a wall?


Amazon

 

 

The Challenge:

We have an Angularjs application. For this challenge we are going to show only the fragment of code necessary to solve the challenge. Below we have the controller, the view and the router. when you navigate to the #/dashboard page you noticed that the controller is executed twice by placing a breakpoint in your browser console. This makes the analyticsServices.save() method to execute twice duplicating the data in your database. What you would do to prevent angular executing controller twice?

This is the controller

function MyController($scope, userServices, analyticsServices) {

    userServices.get({ id: $scope.currentUserId },
        function(user) {
            analyticsServices.save(user);
        });
}

This is a fragment of the code in the view:

<!-- dashboard.html -->
<div ng-controller="MyController">

<!-- html content -->

</div>

This is the of the router

 .when('/dashboard', {
            templateUrl: '/app/dashboard/dashboard.html',
            controller: 'MyController',
            controllerAs: 'ctr',
            title: 'Dashboard'
});


Solution:

Having the controller defined in the controller property in the router and also defined in the ng-controller in the view, this digested the controller twice. Removing the ng-controller directive from the HTML view can resolve the issue. Alternatively, you can remove the controller: property from the routing directive.


Hope this was helpful, please feel free to leave your comments, share other scenarios, or improve this solution! :)

Prevent flicker when Angular route change until model gets loaded (Mini-Challenge 10) Answer

Check out Mini-challenge 10 Instructions

Answer:route

The $routeProvider service’s resolve property allows delaying of route change until data is loaded.

First define a route with resolve attribute like this.

angular.module('myApp', ['myAppFilters', 'myAppServices', 'myAppDirectives']).
  config(['$routeProvider', function($routeProvider) {
    $routeProvider.
      when('/users', {
        templateUrl: 'partials/user-list.html', 
        controller: userListCtrl, 
        resolve: userListCtrl.resolve}).
      when('/users/:userId', {
        templateUrl: 'partials/user-detail.html', 
        controller: userDetailCtrl, 
        resolve: userDetailCtrl.resolve}).
      otherwise({redirectTo: '/users'});
}]);

Notice that the resolve property is defined on the route.

function userListCtrl($scope, users) {
  $scope.users = users;
}

userListCtrl.resolve = {
  users: function(user, $q) {
    var deferred = $q.defer();
    user.query(function(successData) {
            deferred.resolve(successData); 
    }, function(errorData) {
            deferred.reject(); 
    });
    return deferred.promise;
  },
  delay: function($q, $defer) {
    var delay = $q.defer();
    $defer(delay.resolve, 1000);
    return delay.promise;
  }
}

 

Notice that the controller definition contains a resolve object which declares users prop which should be available to the controller constructor and gets injected as dependency and it is defined in the resolve property.

The resolve.users function is responsible for returning a promise. All of the promises are collected and the route change is delayed until after all of the promises are resolved, in this example we are delaying the promise to better illustrate the example.

 

References:

https://docs.angularjs.org/api/ngRoute/provider/$routeProvider

If you have a solution for this challenge, different from the proposal solution on this post, don’t be shy and share it with us :)

Prevent flicker when Angular route change until model gets loaded (Mini-Challenge 10)

Mini-Challenge 10

ng-challenge modelAngularJs Mini-Challenges is a growing collection of “Challenges” about the most quirky parts of the AngularJs framework. It encourage you to find and fix common mistakes and subtle bugs, as well as performance issues and bad practices, that non-expert AngularJs programmers may encounter on their endeavours into the depths of the framework.

AngularJs Mini-Challenges does not aim to teach you AngularJs. Former knowledge of the Framework is strongly recommended in order to understand the topics covered in this Challenges. In order to learn the basics of the Framework, please head over to this excellent book:

 

book

Book Tip

ng-book – The Complete Book on AngularJS
Ready to master AngularJS? What if you could master the entire framework – with solid foundations – in less time without beating your head against a wall?


Amazon

 

 

The Challenge:

Sometimes it happen that when you navigate from one route to another, and you are using services to call apis and fetch the model, the html view gets loaded first provoking a flick.

This is an example of what we want to achieve with this challenge, if there were a PeopleController that listed all Projects and people.html which is the html template that shows the list of peoples, MyService.PeopleQuery() would be fetched completely before showing the new html page. Until then, the current page would still continue to show.

With the solution that you going to provide for this challenge we also going to prevent that the view show the double curly braces in its raw (uncompiled) form: {{ myVariable }}.
Note:
Notice that using ng-cloak is not the solution, with this directive the HTML is shown, this directive only prevent the view to show the uncompiled angular.
ngCloak Documentation

 

Here you can find a possible solution

If you feel that the solution is poor or incomplete or there is room for improvement, please share with every one, you can leave a comment.

How two controllers can communicate between each other (Mini-Challenge 9) Answer

Check out Mini-challenge 9 Instructions

Answer:

There are several ways that one controllers can talk to another, This google group thread, http://groups.google.com/d/topic/angular/m_mn-8gnNt4/discussion, discusses 5 ways controllers can talk to each other.Controllers Mini-Challenge 9 Answer

1. Shared service.
2. Events.
3. Prudent pragmatic use of $root scope.
4. Watchers.
And a 5th – scope prototypical inheritance?
http://docs.angularjs.org/guide/scope

For a sake of simplicity we are going to show a possible answer to this challenge with Events, using $broadcasting and $on:
This is the view:

<div>
<div ng-controller="Ctrl1">
        <input type="text" ng-model="foo" />
        <input type="button" value="Talk to Ctrl2" ng-click="talkToCtrl2()" />
    </div>
<div ng-controller="Ctrl2">{{foo}}</div>
</div>

And this is the javascript:

var myApp = angular.module('myApp', []);


myApp.controller('Ctrl1', myController);
myController.$inject = ['$scope', '$rootScope']

function myController($scope, $rootScope) {
    $scope.foo = "setted in ctrl1";
    $scope.talkToCtrl2 = function () {
		$rootScope.$broadcast('emitedFromController1', $scope.foo);
    }
};

myApp.controller('Ctrl2', myController2);
myController2.$inject = ['$scope']

function myController2($scope) {
    $scope.foo = "setted in ctrl2";
     $scope.$on('emitedFromController1', function(event, args) {
     	$scope.foo = args;
     });

};

In the talkToCtrl2 function we can implement $rootScope.$broadcast(’emitedFromController1′, $scope.foo); and then in the second controller we can implement:
$scope.$on(’emitedFromController1′, function(event, args) {
$scope.foo = args;
});

You can see a working example in this jsFiddle:

If you have a solution for this challenge, different from the proposed solution on this post, don’t be shy and share it with us :)

How two controllers can communicate between each other (Mini-Challenge 9)

Mini-Challenge 9

ng-challenge controllersAngularJs Mini-Challenges is a growing collection of “Challenges” about the most quirky parts of the AngularJs framework. It encourage you to find and fix common mistakes and subtle bugs, as well as performance issues and bad practices, that non-expert AngularJs programmers may encounter on their endeavours into the depths of the framework.

AngularJs Mini-Challenges does not aim to teach you AngularJs. Former knowledge of the Framework is strongly recommended in order to understand the topics covered in this Challenges. In order to learn the basics of the Framework, please head over to this excellent book:

 

book

Book Tip

ng-book – The Complete Book on AngularJS
Ready to master AngularJS? What if you could master the entire framework – with solid foundations – in less time without beating your head against a wall?


Amazon

 

The Challenge:

I have two controllers in an AngularJs application, I need to make a change to a variable in one controller and click a button that will going to talk to the second controller, lets suppose we have this in the View:

<div>
<div ng-controller="Ctrl1">
        <input type="text" ng-model="foo" />
        <input type="button" value="Talk to Ctrl2" ng-click="talkToCtrl2()" />
    </div>
<div ng-controller="Ctrl2">{{foo}}</div>
</div>

 

And then we have this in the controllers:

var myApp = angular.module('myApp', []);

myApp.controller('Ctrl1', myController);

myController.$inject = ['$scope']

function myController($scope) {
$scope.foo = "setted in ctrl1";
$scope.talkToCtrl2 = function () {
//Implement this function
}
};

myApp.controller('Ctrl2', myController2);

myController2.$inject = ['$scope']

function myController2($scope) {
$scope.foo = "setted in ctrl2";

};

The challenge for you is to implement the talkToCtrl2() function, so when you click the button the data in the input text get passed to Ctrl2 and gets printed in the view.
Here is a working example in jsFiddle:

Here you can find a possible solution

If you feel that the solution is poor or incomplete or there is room for improvement, please share with every one, you can leave a comment.

angular set focus on input field (Mini-Challenge 8) Answer

Check out Mini-challenge 8 Instructions (angular set focus)

Answer:

The Angular way to set the focus to an element inside a modal, is with a directive (since this is related to the DOM and Events).

When a Modal is opened, set focus on a predefined <input> inside this Modal.angular set focus
Define a directive and have it $watch a property/trigger so it knows when to focus the element:

Name: <input type="text" focus-me="isOpen">

 

app.directive('focusMe', function($timeout, $parse) {
  return {
    //scope: true,   // optionally create a child scope
    link: function(scope, element, attrs) {
      var model = $parse(attrs.focusMe);
      scope.$watch(model, function(value) {
        if(value === true) { 
          $timeout(function() {
            element[0].focus(); 
          });
        }
      });
      // on blur event:
      element.bind('blur', function() {
         scope.$apply(model.assign(scope, false));
      });
    }
  };
});

Notice that we also added a code for when the element loose the focus (blur) it sets the isOpen property back to false.

Here is a working example:
http://jsfiddle.net/7L8vqf8u/3/

Recommendations:

It is highly recommended try to avoid as much as possible the use of the $watch service. This is another possible solution using angular events:

app.directive('focusOn', function($timeout) {
   return function(scope, element, attrs) {
      scope.$on(attr.focusOn, function(e) {
          $timeout(function() {
            element[0].focus(); 
          });
      });
   };
});

 

Now you can put your directive in the view:

<input type="text" focus-on="isOpen" />

 

and then, in your controller:

$scope.open = function () {
    $scope.$broadcast('isOpen');
};

 

book

Book Tip

ng-book – The Complete Book on AngularJS
Ready to master AngularJS? What if you could master the entire framework – with solid foundations – in less time without beating your head against a wall?


Amazon

 

If you have a better solution on how angular set focus, for this challenge, different from the proposed solution on this post, don’t be shy and share it with us :) you can leave a message on this blog or you can twit me @JoMendezdev.

Focus on input field in AngularJS (Mini-Challenge 8)

Mini-Challenge 8

ng-challengeAngularJs Mini-Challenges is a growing collection of “Challenges” about the most quirky parts of the AngularJs framework. It encourage you to find and fix common mistakes and subtle bugs, as well as performance issues and bad practices, that non-expert AngularJs programmers may encounter on their endeavours into the depths of the framework.

AngularJs Mini-Challenges does not aim to teach you AngularJs. Former knowledge of the Framework is strongly recommended in order to understand the topics covered in this Challenges. In order to learn the basics of the Framework, please head over to this excellent book:

 

book

Book Tip

ng-book – The Complete Book on AngularJS
Ready to master AngularJS? What if you could master the entire framework – with solid foundations – in less time without beating your head against a wall?


Amazon

 

The Challenge:

What is the ‘Angular way’ to set focus on input field in AngularJS?

More specific requirements:

  1. When a Modal pop-up is opened, set focus on a predefined <input> inside this Modal.

I tried to achieve the first requirement with autofocus, but this works only when the Modal is opened for the first time, and only in certain browsers (e.g. in Firefox it doesn’t work). What would be and elegant way to solve this problem?

 

HTM Code:

<div ng-controller="ModalController">
    <button class="btn" ng-click="open()">Click to Open Modal </button>
<div modal="isOpen" close="close()">
<div class="modal-header">
<h4>Modal</h4>
        </div>
<div class="modal-body">
            Name: <input type="text" autofocus>
        </div>
<div class="modal-footer">
 <button class="btn btn-warning cancel" ng-click="close()">Cancel</button>
        </div>
    </div>
</div>

 

Here you can find a working example:

Here you can find a possible solution

If you feel that the solution is poor or incomplete or there is room for improvement, please share with every one, you can leave a comment.

 

Insert conditional css class in AngularJs (Mini-challenge 7) Answer

Check out Mini-challenge 7 Instructions

Answer:Insert conditional css class in AngularJs (Mini-challenge 7) Answer

 

In this case you have an array of object that is rendered in a ul with an li for each element and a property on the controller called selectedIndex.
In this scenario we have to Insert conditional css class in the htmls view.

Insert conditional css class

Using the ng-class directive should be the answer.
The simplest way to implement conditional css class in angular is using the object notation within the ng-class directive.

<li ng-class="{green: $index==selectedIndex}">

With this object notation ({green: $index==selectedIndex}), we can put a condition on where we want to apply the css class. In this specific case we are using the $index build-in variable for ng-repeat, like this.

<div ng-controller="Ctrl">  
<ul>
    <li ng-class="{green: $index==selectedIndex}" ng-repeat="item in list"> <!--apply "green" class to the 3er element -->
       {{item.name}}
    </li>
</ul>
</div>

Here is the ng-class official documentation:
https://docs.angularjs.org/api/ng/directive/ngClass

See working codde below:

If you have a solution for this challenge, different from the proposed solution on this post, don’t be shy and share it with us :)

conditional css class AngularJs (Mini-challenge 7)

conditional css class AngularJs Mini-Challenge 7

conditional css class AngularJsAngularJs Mini-Challenges is a growing collection of “Challenges” about the most quirky parts of the AngularJs framework. It encourage you to find and fix common mistakes and subtle bugs, as well as performance issues and bad practices, that non-expert AngularJs programmers may encounter on their endeavours into the depths of the framework.

AngularJs Mini-Challenges does not aim to teach you AngularJs. Former knowledge of the Framework is strongly recommended in order to understand the topics covered in this Challenges. In order to learn the basics of the Framework, please head over to this excellent book:

 

book

Book Tip

ng-book – The Complete Book on AngularJS
Ready to master AngularJS? What if you could master the entire framework – with solid foundations – in less time without beating your head against a wall?


Amazon

 

The Challenge:

For this challenge we have an object array that is rendered in a ul with an li for each element, also we have a property on the controller called selectedIndex. What would be the best way to add a css class to the li if the index of the array is equal to selectedIndex in AngularJS?

View:
The challenge here is to find the best approach to insert conditional css class AngularJs. This is how the view code looks like, the challenge for you is to find a solution

<div ng-controller="Ctrl">
<ul>
<li class="green" ng-repeat="item in list"> <!--apply "green" class to the 3er element -->
       {{item.name}}
    </li>
</ul>
</div>

Controller:
In the controller we have an array of objects that we are going to render using the ng-repeat on the view. Also we want render the 3rd element with a custom class defined in the

  • html element. We omitted the controller definition in this code example, you can find a more completed doe in the jsfiddle we provided below.

    function Ctrl($scope) {
        $scope.list = [
            {"name": "Item 1", "disposition": "true"},
            {"name": "Item 2", "disposition": "false"},
            {"name": "Item 3", "disposition": "true"},
            {"name": "Item 4", "disposition": "false"},
            {"name": "Item 5", "disposition": "true"}
        ];
    $scope.selectedItem = 3;
    }
    

    See jsfiddle: https://jsfiddle.net/fmdhgho9/4/

    Here you can find a possible solution

    If you feel that the solution is poor or incomplete or there is room for improvement, please share with every one, you can leave a comment.