Month: May 2015

Dependency injection issue when minify the js (Mini-challenge 4) Answer

Check out Mini-challenge 4 Instructions

Answer:dependency injection minify challenge

The parameters to the component (e.g. controller, factory, etc)  for dependency injection, will be converted to mangled variables. For example, $scope and $timeout may become a or b and not be found by Angular in the code inside the controller, factory, etc.

For example this:

(...)
myApp.controller('MyCtrl', function ($scope, $timeout) {
(...)
}
});

Could be converted in something like this.

(...)
myApp.controller('MyCtrl', function (a, b) {
(...)
}
});

If you don't use the $inject service and pass the array of dependencies, you could have errors in your application (see possible solution below).

Solution before minification:

Solution after minification:

You can visit John Papa's angular-styleguide for more information:

https://github.com/johnpapa/angular-styleguide#manual-annotating-for-dependency-injection

This is Todd Motto recommendation for dependency injection annotation:

http://toddmotto.com/angular-js-dependency-injection-annotation-process/ 

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. 🙂

Dependency injection issue when minify the js (Mini-challenge 4)

Mini-challenge 4

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:

We have the following Angular app and we need to minify the code, in the controller of the application we are injecting two services $scope and $timeout (see controller below), we are having errors with the injection when we minify the code:

The view:

<div><button id="btn" type="button">Click me</button>
<div>{{name}}</div>
</div>

 

The controller:

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

myApp.controller('MyCtrl', function ($scope, $timeout) {

document.getElementById('btn').onclick = function (e) {
$timeout(function () {
$scope.name = "Button clicked";
});
}
});

This application works without any issue (see code on jsfiddle).

The js code needs to be minified, after the minification, we started receiving errors in the browser console, see jsfiddle with minified js code:

What you should change in the js code in order to avoid errors when minifying Angular code

Notes:
You can use this online tool to minify js code: http://jscompress.com/

 

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 to reset scope data to initials value (angular.copy) (Mini-challenge 3) Answer

Check out Mini-challenge 3 Instructions

Answer:

angular.copy challengeIn JavaScript when you copy a variable to another variable, like in the code below, the contain of the variable is get passed by reference and not by value, so when you update the origin variable, the destination variable gets updated too and vice versa:

var var1 = ['value1','value2','value3'];
var var2 = var1;

var2[1] = 'different value';

console.log(var1);
console.log(var2);

/*//result
var1: ["value1", "different value", "value3"]
var2: ["value1", "different value", "value3"]
*/

If you run the code above you will notice the value gets updated in both variables, this happened because JavaScript copy the data by reference not by value. The "Angular way" to solve this problem is with the copy method of the angular object: angula.copy().

var var1 = ['value1','value2','value3'];
var var2 = var1;
var var2 = angular.copy(var2);

var2[1] = 'different value';

console.log(var1);
console.log(var2);

/*//result
var1: ["value1", "value2", "value3"]
var2: ["value1", "different value", "value3"]
*/

 

There are few techniques to achieve this with JavaScript, check out this link:
http://stackoverflow.com/questions/728360/most-elegant-way-to-clone-a-javascript-object

 

This is a jsfiddle code to illustrate this method:

You can find more information here:

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. 🙂

Scoping scope (Mini-challenge 2) Answer

 

Check out Mini-challenge 2 Instructions

Answer:

To scoping the scope and avoid this behavior, one solution is to create an object inside the scope instead of call the property scoping scopedirectly from the scope, like this: $scope.obj.myProp (see code below).

 

myApp.controller('navCtrl', function ($scope) {
    $scope.obj = {};
});

 
In the view:

<div ng-controller="navCtrl">
   <div>navCtrl text: {{obj.name}}</div>
   <div ng-controller="loginCtrl">
        <div> loginCtrl text: {{obj.name}}</div>
       <br/>
        <input ng-model="obj.name"></input>
   </div>
</div>

 

Here are other recommendations and references.:

https://www.airpair.com/angularjs/posts/top-10-mistakes-angularjs-developers-make#8-scoping-scope-s
You can find more information about the angularjs scope and the Prototypal Inheritance here.
https://github.com/angular/angular.js/wiki/Understanding-Scopes

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. 🙂

How to reset scope data to initials value (Mini-challenge 3)

Mini-challenge 3

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:

We have an Angular application where we want to create a starting point with the "default" data in the Angular scope, so we can create a reset button and restore the scope to the initial values.

the controller:

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

function myCtrl($scope) {
    $scope.data = [{
        text: 'Lorem ipsum dolor sit amet',
        text2: 'consectetur adipiscing elit'
    }, {
        text: ' Nullam eu molestie mi',
        text2: 'Proin eu congue nisi.'
    }];

    $scope.origData = $scope.data;

    $scope.reset = function () {
        $scope.data = $scope.origData;
    };

}

This is the view:

<div ng-controller="myCtrl">
Modify the text in the inputs: 
<div ng-repeat="item in data"> <input type="text" ng-model="item.text"/> 
<input type="text" ng-model="item.text2"/> 
</div>
    <button type="button" ng-click="reset()">Reset</button>
</div>

Here is the fiddlejs: 

 

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 code example above is not working because when a JavaScript object (such as $scope.origData) is assigned to a variable, it is assigned by reference, not by value, the point of this challenge is to find a solution to make the reset button works.

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.

Scoping scope (Mini-challenge 2)

Mini-challenge 2

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:

We have an Angular application with two nested controllers, the requirement is that when the user input a text into the TextBox the “user” variable get updated in both places where it is bound in the view, but when we entering text into the input text, only one "user" variable gets updated. You can see the JsFiddle below:

This is the View:

<div ng-controller="navCtrl">
<div>navCtrl text: {{user}}</div>
<div ng-controller="loginCtrl">
<div> loginCtrl text: {{user}}</div>
        <input ng-model="user"></input>
   </div>
</div>

In the controller we use the scope  to bind the "user" variable

This is the controllers:

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

myApp.controller('navCtrl', function ($scope) {
      $scope.user = "";
});

myApp.controller('loginCtrl', function ($scope) {

});

 

Here is a jsfiddle with the code.:

The problem is that only loginCtrl’s “user” variable is getting updated. The challenge consist in find a solution to this problem.

 

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.

Problem when using JS events in AngularJs (Mini-Challenge 1)

Mini-challenge 1

ng-challenge

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:

Lets suppose we have an angular app with a button, when you click that button, a text should appear in the view.
As requirement we have to handle the onclick event of the button with vanillaJs.
E.g.
document.getElementById('btn').onclick = function (e) {
...
});

This is how the view looks like:

<div><button id="btn" type="button">Click me</button>
<div>{{name}}</div>
</div>

This is how the controller looks like:

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

myApp.controller('MyCtrl', function ($scope) {

document.getElementById('btn').onclick = function (e) {
$scope.name = "Button clicked";
}
});

Here is a jsfiddle with the code:

Notes:

Even when for this challenge you can't use directives (see the constraint above), I strongly recommend to use directives to handling events all the time, when working with angularJs, try to avoid to use JavaScript Event handling in real life projects.
For the sake of this challenge as a constraints requirements, we can’t use the ng-click directive.
As a result, the code doesn't work, so, the challenge is to solve it without use ng-* angular directive.

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.

Problem when using JS events in AngularJs (Mini-Challenge 1) Answer

Check out Mini-challenge 1 Instructions

Answer:js event angular

The fastest and more effective answer is to wrap up the code you want to deffer (event or AJAX call) within an AngularJs $timeout() function, see the code below:

myApp.controller('MyCtrl', function ($scope, $timeout) {

    document.getElementById('btn').onclick = function (e) {
        $timeout(function () {
            $scope.name = "Button clicked";
        });
    }
});

 

Recommendations and References:

Try to avoid to use this:

if(!$scope.$$phase) {
     //$digest or $apply
}

$$phase is indeed private to the framework and there are good reasons for that

$timeout(callback) will wait until the current digest cycle (if any) is done, then execute your code, then run at the end a full $apply.

$timeout(callback, delay, false)will do the same (with an optional delay before executing your code), but won’t fire an $apply which saves performances if you didn’t modify your model.

$apply invokes, among other things, $root.$digest, which means it will redigest the root scope and all of its children, even if you’re within an isolated scope.

$digest will simply sync its scope model to view, but won’t tell its parents scope, which can save a lot of performances when working on an isolated part of your HTML with an isolated scope (from a directive).

$evalAsync has been introduced with angularjs 1.2, that will probably solve most of your troubles.

if you get the “$digest already in progress” error, then your architecture is wrong: either you don’t need to re-digest your scope, or you should not be in charge of that.

 

More resources

http://www.bennadel.com/blog/2605-scope-evalasync-vs-timeout-in-angularjs.htm
http://www.jomendez.com/2015/02/09/best-practice-to-include-code-within-the-cycle-digest/
http://www.bennadel.com/blog/2751-scope-applyasync-vs-scope-evalasync-in-angularjs-1-3.htm

Go to the solution link above, for more recommendations.

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 🙂