AngularJS

Q1. What is AngularJS, and how does it differ from traditional JavaScript frameworks?

Answer:

AngularJS is a structural JavaScript framework for building dynamic web applications. It extends HTML with additional attributes and uses two-way data binding to synchronize the model and view automatically. Unlike traditional frameworks, it uses the MVC (Model-View-Controller) architecture and promotes modular, testable code.

Answer:

Directives are special tokens in the DOM that tell AngularJS to extend HTML functionality. Built-in directives include ng-model, ng-bind, and ng-repeat.

<input type="text" ng-model="name">
<p>Hello, {{name}}!</p>
Answer:

$scope is an object that binds the controller and view, enabling data exchange. It serves as a “glue” between them, where any properties or functions on $scope become accessible in the view.

app.controller('MainController', function($scope) {
  $scope.greeting = "Hello, World!";
});
Answer:

Two-way data binding allows the model and view to be updated automatically in sync. When data in the model changes, it reflects in the view, and vice versa.

Answer:

AngularJS is built on the MVC pattern, where:

  • Model represents data.
  • View displays data.
  • Controller manages the interaction between model and view.
Answer:

ng-app initializes an AngularJS application and sets the root element for Angular components.

<div ng-app="myApp">
  <!-- AngularJS app content -->
</div>
Answer:

ng-repeat is used to repeat an element for each item in a collection, commonly for displaying lists.

<ul>
  <li ng-repeat="item in items">{{item.name}}</li>
</ul>
Answer:

Services are singleton objects in AngularJS used for logic that needs to be reused across the app, such as data sharing, network requests, and more.

Answer:

Dependency injection in AngularJS is a way to manage dependencies between components by injecting services into controllers or other components, making code modular and testable.

Answer:

$http is an AngularJS service for making HTTP requests, allowing data retrieval from external APIs.

$http.get('/api/data').then(response => {
  $scope.data = response.data;
});
Answer:

Custom directives are user-defined DOM elements or attributes that extend HTML functionality. They’re registered with the directive method.

app.directive('myDirective', function() {
  return {
    template: '<p>This is a custom directive</p>'
  };
});
Answer:

$watch is used to monitor changes to a variable on the $scope. When the variable changes, a callback is triggered.

$scope.$watch('name', function(newVal, oldVal) {
  console.log('Name changed from', oldVal, 'to', newVal);
});
Answer:

$digest updates the bindings, while $apply triggers $digest and also allows execution of external functions inside Angular’s scope.

Answer:

$routeProvider enables routing, allowing different views and controllers based on URL routes.

app.config(function($routeProvider) {
  $routeProvider
    .when('/home', { templateUrl: 'home.html', controller: 'HomeController' });
});
Answer:

ng-submit binds a form submission to an AngularJS expression or function in the controller.

<form ng-submit="submitForm()">
  <!-- Form fields -->
</form>
Answer:

Filters format data for display, such as uppercase, lowercase, currency, and date filters.

<p>{{ price | currency }}</p>
Answer:

$timeout is a wrapper around JavaScript’s setTimeout, ensuring execution within Angular’s digest cycle.

$timeout(function() {
  $scope.message = "Hello, AngularJS!";
}, 1000);
Answer:

$compile is a service that compiles HTML strings or DOM elements into a template, linking it with a scope. It’s often used in custom directives to add dynamic behavior to elements.

const compiledElement = $compile('<div>{{message}}</div>')($scope);
Answer:

ng-include allows you to include external HTML files within a template. This is useful for breaking down large templates into smaller, reusable components.

<div ng-include="'header.html'"></div>
Answer:

ng-init initializes variables in the view, useful for simple values. However, $scope initialization in the controller is better for complex data and logic.

<div ng-init="count=1">{{count}}</div>
Answer:

$broadcast sends an event down the scope hierarchy, reaching all child scopes. $emit sends an event up, notifying only ancestor scopes. Both are used for inter-component communication.

Answer:

$q is AngularJS’s promise service for handling asynchronous operations, similar to JavaScript promises, but integrated within Angular’s digest cycle, making it ideal for chaining.

$q.when(data).then(result => { console.log(result); });
Answer:

$timeout is Angular’s version of setTimeout and is integrated into the digest cycle, ensuring AngularJS data binding is updated after timeout.

Answer:

$resource is a service for interacting with RESTful APIs. It simplifies HTTP requests by creating a higher-level abstraction over $http.

const User = $resource('/api/users/:id');
Answer:

Use $scope.$evalAsync() to delay expressions until after the current digest cycle, preventing redundant cycle triggers in custom directives.

Answer:

$location manages the URL in a single-page application (SPA) and facilitates navigation without reloading the page, handling path, hash, and search parameters.

$location.path('/newPath');
Answer:

$parse converts AngularJS expressions into functions, allowing dynamic evaluation of strings as expressions in custom directives and controllers.

const parsedFn = $parse('user.name');
Answer:

$provide is responsible for configuring, defining, and injecting services, constants, and factories in an AngularJS application, making it a key service in dependency injection.

Answer:

$scope.$applyAsync schedules an expression to be run after the current digest cycle, reducing excessive digest cycles and enhancing performance.

Answer:

Interceptors intercept and modify HTTP requests or responses. They’re used for tasks like adding headers, handling errors, or logging.

$httpProvider.interceptors.push('myInterceptor');
Answer:

AngularJS promises with $q are used for asynchronous operations. $q allows the creation, resolution, and chaining of promises in Angular applications.

const deferred = $q.defer();
Answer:

$watchCollection monitors changes in collections (arrays or objects) without tracking individual properties. It’s useful for detecting additions or deletions in arrays.

Answer:

Lazy loading loads components only when needed, improving initial load speed. This can be implemented by dynamically injecting modules or using route-based lazy loading.

Answer:

$cacheFactory creates caches for storing data, reducing redundant API calls and improving performance by reusing cached results.

const cache = $cacheFactory.get('$http');
Answer:

Use $exceptionHandler to handle exceptions globally. Override this service to capture and log errors, providing centralized error management.

Answer:

$evalAsync schedules expressions for the next digest cycle without triggering a new cycle. It’s used to prevent multiple $digest calls.

Answer:

ng-annotate automates adding dependency annotations in AngularJS, especially useful for minification, ensuring Angular services are injected correctly in minimized code.

Answer:

AngularJS uses dependency injection (DI) to inject services, factories, or values into components, enhancing modularity and testability. In production, DI optimization involves minification-safe annotations like ng-annotate or array-style syntax to prevent errors from variable renaming. This helps avoid runtime failures and keeps the code maintainable.

angular.module('myApp', [])
  .controller('MainController', ['$scope', 'DataService', function($scope, DataService) {
    // Controller code here
  }]);
Answer:

A digest cycle checks scope variables for changes to update the DOM. Overuse of $watch or unnecessary cycles degrade performance, especially with large datasets. Optimizing cycles with $applyAsync or $evalAsync in custom directives can minimize performance issues and improve responsiveness in AngularJS applications.

Answer:

$q allows creating and chaining custom promises, suitable for handling complex async tasks. By using $q.defer(), we can manage promise resolution or rejection and streamline complex async workflows with then(), all(), and catch() for handling errors.

function getData() {
  var deferred = $q.defer();
  $http.get('/api/data').then(response => {
    deferred.resolve(response.data);
  }, error => {
    deferred.reject(error);
  });
  return deferred.promise;
}
Answer:

$timeout and $interval are Angular wrappers for setTimeout and setInterval, integrated with the digest cycle. They ensure model updates are reflected in the DOM. To prevent memory leaks, use $timeout.cancel() and $interval.cancel() for clean-up, especially for ongoing tasks.

var interval = $interval(function() {
  console.log("Repeating task");
}, 1000);

// Cancel the interval
$interval.cancel(interval);
Answer:

$applyAsync defers expressions until the next digest cycle, reducing digest cycle triggers and consolidating updates. It’s valuable in scenarios with frequent updates, as it optimizes performance by minimizing digest overload, making applications more responsive.

$scope.incrementAsync = function() {
  $scope.$applyAsync(() => {
    $scope.counter++;
  });
};
Answer:

$http interceptors intercept requests/responses, useful for adding auth tokens or handling errors globally. For API authentication, an interceptor can attach JWT tokens to headers, enhancing maintainability by centralizing auth handling.

app.factory('authInterceptor', function() {
  return {
    request: function(config) {
      config.headers.Authorization = 'Bearer token';
      return config;
    }
  };
});
$httpProvider.interceptors.push('authInterceptor');
Answer:

Prevent memory leaks by deregistering $watch listeners, cancelling $timeout and $interval, and managing $scope.$on listeners with $destroy. Chrome DevTools and profiling tools help monitor active listeners and retained objects, making it easier to identify and fix memory leaks.

var unwatch = $scope.$watch('variable', function(newValue) {
  // Watcher code
});
$scope.$on('$destroy', unwatch);
Answer:

$broadcast sends events to child scopes, $emit sends events to ancestor scopes, and $on listens for these events. They enable cross-controller communication, though overuse can impact performance and readability. Using services for shared data may be more efficient in large applications.

$scope.$emit('eventName', data); // Emit to ancestor scopes
Answer:

Lazy loading delays module loading until needed, improving performance by reducing initial load time. Using libraries like ocLazyLoad or route-based lazy loading are effective strategies, ensuring only required modules load, speeding up single-page application initialization.

$routeProvider.when('/lazy', {
  templateUrl: 'lazy.html',
  resolve: {
    load: function($ocLazyLoad) {
      return $ocLazyLoad.load('lazyModule.js');
    }
  }
});
Answer:

$compileProvider adjusts directives’ behavior, allowing configuration like transclusion, priority, and scope. It optimizes performance by setting $compileProvider.debugInfoEnabled(false) in production, reducing data binding overhead and enhancing directive efficiency.

Answer:

$cacheFactory caches data, reducing redundant API calls and resource usage by storing frequently accessed data. This approach lowers server load and improves responsiveness by ensuring that cached results are reused instead of fetched repeatedly.

var cache = $cacheFactory('myCache');
cache.put('key', 'value');
Answer:

$provide.decorator modifies existing services by wrapping them, adding functionality like logging or custom behavior while preserving original functionality. This is useful for adjusting services, adding logging or profiling, without changing source code, enhancing flexibility and control.

$provide.decorator('$log', function($delegate) {
  return function(msg) {
    $delegate(msg + ' decorated');
  };
});
Answer:

ngModelOptions provides advanced control over model updates, including debounce for delayed updates, getterSetter for custom get/set functions, and allowInvalid for validation handling. This fine-grained control improves form performance, especially with high-frequency data changes.

<input type="text" ng-model="name" ng-model-options="{ debounce: 500 }">

Answer:

$rootScope.$digest manually starts a digest cycle, updating all scopes. Triggering it manually can be useful in third-party library events or complex custom directives, but overuse can degrade performance, so $apply is often preferable for scope-limited updates.

Answer:

$rootScope.$on listens for events across the entire app, useful for global event handling. However, extensive use can lead to memory leaks and scope pollution, so it’s better to use it selectively and manage listeners to prevent performance issues.

$rootScope.$on('event', function(event, data) {
  console.log(data);
});
Answer:

Services are singletons instantiated with new, factories return objects, and providers offer the most configuration flexibility, available during the config phase. Providers are ideal for complex setups, while services and factories are better for general dependency injection and logic reuse.

Answer:

$provide.constant defines unmodifiable values accessible across an app, useful for config data like API URLs. Unlike services, constants are accessible in config blocks, making them available early for consistent app-wide settings.

app.constant('API_URL', 'https://api.example.com');
Answer:

AngularJS modules encapsulate code for better organization, using dependencies to include other modules automatically. Dependencies allow seamless integration of shared features, reducing duplication and facilitating module-based code reuse and maintenance across large projects.

Answer:

One-time binding (using ::) binds data once, updating the view only once, ideal for static or rarely changed data. By reducing $watch listeners, it optimizes performance, particularly in data-heavy views or applications with extensive scope bindings.

<p>{{ ::data }}</p>
Answer:

$httpBackend mocks HTTP requests, enabling testing without actual server calls. It’s used to simulate $http calls, allowing predictable tests and error handling. With expectGET() and .flush(), $httpBackend enables robust, isolated tests for HTTP-dependent components.

$httpBackend.expectGET('/api/data').respond(200, { data: 'mockData' });
$httpBackend.flush(); // Triggers the mock response