Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I stop Angular.js’s json filter from excluding properties that start with $?

Angular.js has a handy built-in filter, json, which displays JavaScript objects as nicely formatted JSON.

However, it seems to filter out object properties that begin with $ by default:

Template:

<pre>{{ {'name':'value', 'special':'yes', '$reallyspecial':'Er...'} | json }}</pre>

Displayed:

{
  "name": "value",
  "special": "yes"
}

http://plnkr.co/edit/oem4HJ9utZMYGVbPkT6N?p=preview

Can I make properties beginning with $ be displayed like other properties?

like image 545
Paul D. Waite Avatar asked Apr 03 '14 09:04

Paul D. Waite


People also ask

What is the use of JSON filter in AngularJS?

The json filter in AngularJs is used to convert a JavaScript object into a JSON. string.JavaScript object that we are using can be of any kind of JavaScript Object.

What is this JavaScript Object filter for?

This filter can be useful when debugging your applications. The JavaScript object can be any kind of JavaScript object. Optional. A number specifying how many spaces to user per indentation. The default value is 2

How to filter for specific URLs in web applications?

2. Filter for Specific URLs Let's say our web application needs to log some information about its requests, such as their paths and content types. One way to do this is by creating a logging filter. 2.1. Logging Filter

What is the difference between JSON and spacing in JSON?

Where json is used to specifies that object should be displayed in JSON format and spacing is an optional parameter with default value 2 that specifies the number of spaces per indentation.


1 Answers

Basically you can't. It is "hard-coded" into the filter's behaviour.
Nonetheless, it is quite easy to build a custom JSON filter that behaves identically with the Angular's one but not filtering out properties starting with '$'.

(Scroll further down for sample code and a short demo.)


If you take a look at the 1.2.15 version source code, you will find out that the json filter is defined like this:

function jsonFilter() {
  return function(object) {
    return toJson(object, true);
  };
}

So, it uses the toJson() function (the second parameter (true) means: format my JSON nicely).


So, our next stop is the toJson() function, that looks like this:

function toJson(obj, pretty) {
  if (typeof obj === 'undefined') return undefined;
  return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
}

This function makes use of the "native" JSON.stringify() function, passing a custom replacer function (toJsonReplacer).


The toJsonReplacer() function handles some special cases: It checks if the key starts with $ and ignores it if it does (this is what we want to change) and it checks if the value is either a Window, a Document or a Scope object (in which case it converts it to a descriptive string in order to avoid "Converting circular structure to JSON" errors).

function toJsonReplacer(key, value) {
  var val = value;

  if (typeof key === 'string' && key.charAt(0) === '$') {
    val = undefined;
  } else if (isWindow(value)) {
    val = '$WINDOW';
  } else if (value &&  document === value) {
    val = '$DOCUMENT';
  } else if (isScope(value)) {
    val = '$SCOPE';
  }

  return val;
}

For the sake of completeness, the two functions that check for Window and Scope look like this:

function isWindow(obj) {
  return obj && obj.document && obj.location && obj.alert && obj.setInterval;
}

function isScope(obj) {
  return obj && obj.$evalAsync && obj.$watch;
}

Finally, all we need to do is to create a custom filter that uses the exact same code, with the sole difference that our toJsonReplacer() won't filter out properties starting with $.

app.filter('customJson', function () {
    function isWindow(obj) {
        return obj && 
               obj.document && 
               obj.location && 
               obj.alert && 
               obj.setInterval;
    }

    function isScope(obj) {
        return obj && 
               obj.$evalAsync && 
               obj.$watch;
    }

    function toJsonReplacer(key, value) {
        var val = value;

        if (isWindow(value)) {
            val = '$WINDOW';
        } else if (value && (document === value)) {
            val = '$DOCUMENT';
        } else if (isScope(value)) {
            val = '$SCOPE';
        }

        return val;
    }

    function toJson(obj, pretty) {
        if (typeof obj === 'undefined') { return undefined; }
        return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
    }

    return function(object) {
        return toJson(object, true);
    };
});

See, also, this short demo.


* The downside is that your custom JSON filter will not benefit from further improvement/enhancement of Angular's json filter, so you'll have to re-define your's to incorporate changes. Of course, for such a basic and simple filter like this, one should'nt expect frequent or extensive changes, but that doesn't mean there aren't going to be any.

like image 123
gkalpak Avatar answered Oct 07 '22 16:10

gkalpak