📜 ⬆️ ⬇️

AngularJs $ parse hacks

I offer a translation of the publication “AngularJs $ parse hacks” .

In the depths of AngularJs, there is one small and wonderful feature: $ parse . It is usually used inside a framework for interpolating values, for example, for two-way data binding:

<p>Hello, {{ user.name }}</p> // where user is an object in the scope 

You can see this simple example here .

To calculate the value of the expression the user.name AngularJs will call $ parse, then put the result in the DOM.
')
$ parse converts expressions , and not just lacks the properties of objects, for example:

 <p>{{ 'Hello ' + user.name }}</p> 

An example can be found here .

You can use $ parse in your code by adding a dependency to the controller (or any other function). Calling $ parse involves two steps: compiling an expression into a template function and then calling that function with context and local variables. Usually the context and local variables are the $ scope object:

 function controller($scope, $parse) { $scope.user = { name: 'Joe' }; var template = $parse('Hello + user.name'); var msg = template($scope); // Hello Joe } 

This two-step execution is also observed in other template libraries, such as Handlebars .

In addition, $ parse forgives a lot, for example, if the $ scope.user object does not exist, the expression is normally converted, but returns undefined, which is displayed as an empty string, an example here . This behavior of the $ parse function resulted in the following hacks:

Hack 1: secure access of nested properties


If we have an object with a property value that can be null, access to the nested properties of this property forces all sorts of checks:

 var foo = { bar: { baz: { name: 'baz' } } }; var name; if (typeof foo === 'object' && typeof foo.bar === 'object' && typeof foo.bar.baz === 'object') { name = foo.bar.baz.name; } 

Of course, you can use a third-party library like l33teral and wrap objects for secure access:

 var leet = require('l33teral'); var fooL = leet(foo); var name = fooL.tap('bar.baz.name'); 

But if you already use AngularJs, then just use $ parse:

 var name = $parse('bar.baz.name')(foo); 

Complete example . If the property does not exist, the call will return undefined:

 $parse('bar.baz2.name')(foo); // returns undefined 

You can also assign the first step to a function in a variable, in order to avoid re-compiling the expression.

 var getName = $parse('bar.baz.name'); ... getName(foo); 


Hack 2: sending logic from the backend to the client


If you need to dynamically run something (calculate) on the client, you can send logic from the server as a string. In the line, in addition to methods, local variables can also be defined, for this $ parse is called with 2 arguments (context and local variables):

 var ops = { add: function (a, b) { return a + b; }, mul: function (a, b) { return a * b; } }; var logic = 'mul(add(a, 1), b)'; var data = { a: 10, b: 4 }; var result = $parse(logic)(ops, data); // 44 

Complete example .

The data argument may override properties in the context of the ops argument, but I recommend keeping methods separate from data for a more understandable implementation.

Hack 3: Spreadsheet in 20 minutes


To demonstrate the power of AngularJs in all its glory, I like to refer to David Graunke's spreadsheet example . This is super awesome, an example that uses $ parse to dynamically transform expressions inside each cell. Expressions can refer to the values ​​of other cells, which in turn can refer to other cells, etc. The basic logic of this example is that all cells are in scope, and the coumpute function is called every time the value of any cell changes.

 function sheetController($scope, $parse) { $scope.columns = ['A', 'B', 'C', 'D']; $scope.rows = [1, 2, 3, 4]; $scope.cells = {}; // will be filled with row x column objects $scope.compute = function(cell) { return $parse($scope.cells[cell])($scope); }; } 

Spreadsheet in action.

Source: https://habr.com/ru/post/244001/


All Articles