Home / Angular / Vlink Interview Questions

Vlink Interview Questions

1. what is the difference between ng-if and ng-show/ng-hide
2. How to create a custom directive
3. What’s the correct way to communicate between controllers in AngularJS?
4. AngularJS: Service vs provider vs factory
5. AngularJS: ng-switch-when with an OR
6. How digest works in angular
7. How route providers works

Solutions :

1. what is the difference between ng-if and ng-show/ng-hide
ngIf

The ngIf directive removes or recreates a portion of the DOM tree based on an expression. If the expression assigned to ngIf evaluates to a false value then the element is removed from the DOM, otherwise, a clone of the element is reinserted into the DOM.

when $scope.myValue is truthy (element is restored)

<div ng-if="1"></div>

when $scope.myValue is falsy (element is removed)

<div ng-if="0"></div>

When an element is removed using ngIf its scope is destroyed and a new scope is created when the element is restored. The scope created within ngIf inherits from its parent scope using prototypal inheritance.

If ngModel is used within ngIf to bind to a JavaScript primitive defined in the parent scope, any modifications made to the variable within the child scope will not affect the value in the parent scope, e.g.

		<input type="text" ng-model="data">
		<div ng-if="true">
			<input type="text" ng-model="data">
		</div>        
		To get around this situation and update the model in the parent scope from inside the child scope, use an object:

		<input type="text" ng-model="data.input">
		<div ng-if="true">
			<input type="text" ng-model="data.input">
		</div>
		Or, $parent variable to reference the parent scope object:

		<input type="text" ng-model="data">
		<div ng-if="true">
			<input type="text" ng-model="$parent.data">
		</div>

ngShow

The ngShow directive shows or hides the given HTML element based on the expression provided to the ngShow attribute. The element is shown or hidden by removing or adding the ng-hide CSS class onto the element. The .ng-hide CSS class is predefined in AngularJS and sets the display style to none (using an !important flag).

		when $scope.myValue is truthy (element is visible)
		<div ng-show="1"></div>

		when $scope.myValue is falsy (element is hidden)
		<div ng-show="0" class="ng-hide"></div>

When the ngShow expression evaluates to false then the ng-hide CSS class is added to the class attribute on the element causing it to become hidden. When true, the ng-hide CSS class is removed from the element causing the element not to appear hidden.

2. How to create a custom directive

In your directive bind your attribute with ngModel :

		app.directive('myDirective', function() {
		  return {
		  restrict: 'AE', 
		  scope: {
			myModel: '=ngModel'
		  },
		  template:'<input ng-model="myModel"/>'
		}});
		You should be able to use is from your HTML like this :

		<my-directive ng-model="whatyouwant"></my-directive>

3. What’s the correct way to communicate between controllers in AngularJS?
Edit: The issue addressed in this answer have been resolved in angular.js version 1.2.7. $broadcast now avoids bubbling over unregistered scopes and runs just as fast as $emit.

use $broadcast from the $rootScope
listen using $on from the local $scope that needs to know about the event

Original Answer Below

I highly advise not to use $rootScope.$broadcast + $scope.$on but rather $rootScope.$emit+ $rootScope.$on. The former can cause serious performance problems as raised by @numan. That is because the event will bubble down through all scopes.

However, the latter (using $rootScope.$emit + $rootScope.$on) does not suffer from this and can therefore be used as a fast communication channel!

From the angular documentation of $emit:

Dispatches an event name upwards through the scope hierarchy notifying the registered
Since there is no scope above $rootScope, there is no bubbling happening. It is totally safe to use $rootScope.$emit()/ $rootScope.$on() as an EventBus.

However, there is one gotcha when using it from within Controllers. If you directly bind to $rootScope.$on() from within a controller, you’ll have to clean up the binding yourself when your local $scope gets destroyed. This is because controllers (in contrast to services) can get instantiated multiple times over the lifetime of an application which would result into bindings summing up eventually creating memory leaks all over the place 🙂

To unregister, just listen on your $scope’s $destroy event and then call the function that was returned by $rootScope.$on.

		angular
			.module('MyApp')
			.controller('MyController', ['$scope', '$rootScope', function MyController($scope, $rootScope) {

					var unbind = $rootScope.$on('someComponent.someCrazyEvent', function(){
						console.log('foo');
					});

					$scope.$on('$destroy', unbind);
				}
			]);

I would say, that’s not really an angular specific thing as it applies to other EventBus implementations as well, that you have to clean up resources.

However, you can make your life easier for those cases. For instance, you could monkey patch $rootScope and give it a $onRootScope that subscribes to events emitted on the $rootScope but also directly cleans up the handler when the local $scope gets destroyed.

The cleanest way to monkey patch the $rootScope to provide such $onRootScope method would be through a decorator (a run block will probably do it just fine as well but pssst, don’t tell anybody)

To make sure the $onRootScope property doesn’t show up unexpected when enumerating over $scope we use Object.defineProperty() and set enumerable to false. Keep in mind that you might need an ES5 shim.


		angular
			.module('MyApp')
			.config(['$provide', function($provide){
				$provide.decorator('$rootScope', ['$delegate', function($delegate){

					Object.defineProperty($delegate.constructor.prototype, '$onRootScope', {
						value: function(name, listener){
							var unsubscribe = $delegate.$on(name, listener);
							this.$on('$destroy', unsubscribe);

							return unsubscribe;
						},
						enumerable: false
					});


					return $delegate;
				}]);
			}]);

With this method in place the controller code from above can be simplified to:


		angular
			.module('MyApp')
			.controller('MyController', ['$scope', function MyController($scope) {

					$scope.$onRootScope('someComponent.someCrazyEvent', function(){
						console.log('foo');
					});
				}
			]);

So as a final outcome of all this I highly advise you to use $rootScope.$emit + $scope.$onRootScope.

Btw, I’m trying to convince the angular team to address the problem within angular core. There’s a discussion going on here: https://github.com/angular/angular.js/issues/4574

Here is a jsperf that shows how much of a perf impact $broadcastbrings to the table in a decent scenario with just 100 $scope’s.

4. AngularJS: Service vs provider vs factory
From the AngularJS mailing list I got an amazing thread that explains service vs factory vs provider and their injection usage. Compiling the answers:

Services

Syntax: module.service( ‘serviceName’, function );
Result: When declaring serviceName as an injectable argument you will be provided with an instance of the function. In other words new FunctionYouPassedToService().

Factories

Syntax: module.factory( ‘factoryName’, function );
Result: When declaring factoryName as an injectable argument you will be provided with the value that is returned by invoking the function reference passed to module.factory.

Providers

Syntax: module.provider( ‘providerName’, function );
Result: When declaring providerName as an injectable argument you will be provided with (new ProviderFunction()).$get(). The constructor function is instantiated before the $get method is called – ProviderFunction is the function reference passed to module.provider.

Providers have the advantage that they can be configured during the module configuration phase.

See here for the provided code.

Here’s a great further explanation by Misko:

		provide.value('a', 123);

		function Controller(a) {
		  expect(a).toEqual(123);
		}
		In this case the injector simply returns the value as is. But what if you want to compute the value? Then use a factory

		provide.factory('b', function(a) {
		  return a*2;
		});

		function Controller(b) {
		  expect(b).toEqual(246);
		}
		So factory is a function which is responsible for creating the value. Notice that the factory function can ask for other dependencies.

		But what if you want to be more OO and have a class called Greeter?

		function Greeter(a) {
		  this.greet = function() {
			return 'Hello ' + a;
		  }
		}

Then to instantiate you would have to write

provide.factory(‘greeter’, function(a) {
return new Greeter(a);
});
Then we could ask for ‘greeter’ in controller like this

function Controller(greeter) {
expect(greeter instanceof Greeter).toBe(true);
expect(greeter.greet()).toEqual(‘Hello 123’);
}
But that is way too wordy. A shorter way to write this would be provider.service(‘greeter’, Greeter);

But what if we wanted to configure the Greeter class before the injection? Then we could write

		provide.provider('greeter2', function() {
		  var salutation = 'Hello';
		  this.setSalutation = function(s) {
			salutation = s;
		  }

		  function Greeter(a) {
			this.greet = function() {
			  return salutation + ' ' + a;
			}
		  }

		  this.$get = function(a) {
			return new Greeter(a);
		  };
		});
		Then we can do this:

		angular.module('abc', []).config(function(greeter2Provider) {
		  greeter2Provider.setSalutation('Halo');
		});

		function Controller(greeter2) {
		  expect(greeter2.greet()).toEqual('Halo 123');
		}
		As a side note, service, factory, and value are all derived from provider.

		provider.service = function(name, Class) {
		  provider.provide(name, function() {
			this.$get = function($injector) {
			  return $injector.instantiate(Class);
			};
		  });
		}

		provider.factory = function(name, factory) {
		  provider.provide(name, function() {
			this.$get = function($injector) {
			  return $injector.invoke(factory);
			};
		  });
		}

		provider.value = function(name, value) {
		  provider.factory(name, function() {
			return value;
		  });
		};

5. AngularJS: ng-switch-when with an OR

		<select ng-model="myVar">
		  <option value="dogs">Dogs
		  <option value="tuts">Tutorials
		  <option value="cars">Cars
		</select>

		<hr>
		<div ng-switch="myVar">
		  <div ng-switch-when="dogs">
			 <h1>Dogs</h1>
			 <p>Welcome to a world of dogs.</p>
		  </div>
		  <div ng-switch-when="tuts">
			 <h1>Tutorials</h1>
			 <p>Learn from examples.</p>
		  </div>
		  <div ng-switch-when="cars">
			 <h1>Cars</h1>
			 <p>Read about cars.</p>
		  </div>
		  <div ng-switch-default>
			 <h1>Switch</h1>
			 <p>Select topic from the dropdown, to switch the content of this DIV.</p>
		  </div>
		</div>

6. How digest works in angular

I think the description of the digest cycle at http://blog.bguiz.com/post/60397801810/digest-cycles-in-single-page-apps that it is

code that runs at an interval
is very misleading, and to be honest, when referring to Angular, I would even say wrong. To quote Pawel Kozlowski, Mastering Web Application Development with AngularJS

AngularJS does not use any kind of polling mechanism to periodically check for model changes
To prove there is no polling if you have a template of

{{state}}

and controller code of

		$scope.state = 'Initial';
		// Deliberately *not* using $timeout here
		$window.setTimeout(function() {
		  $scope.state = 'Changed';
		},1000);

as in this plunker, then the string shown to the user will remain as Initial and never change to Changed.

If you’re wondering why you often see calls to $apply, but not always, it is probably because the various directives that come with Angular, such as ngClick or ngChange will call $apply themselves, which will then trigger the cycle. Event listeners to native JS events directly will not do this, so they will have to deliberately call $apply to have any changes made reflected in templates.


7. How route providers works

var app = angular.module("myApp", ["ngRoute"]);
app.config(function($routeProvider) {
$routeProvider
.when("/", {
templateUrl : "main.htm"
})
.when("/red", {
templateUrl : "red.htm"
})
.when("/green", {
templateUrl : "green.htm"
})
.when("/blue", {
templateUrl : "blue.htm"
});
});

About Mohammad Fareed

Software Engineer @ Tekzenit.

Check Also

Object Creation in Java

1)How many ways are there to create an object? 1. How many ways to create …

Leave a Reply

Your email address will not be published. Required fields are marked *