86

Here I have a complex data structure in an Angular4 application.

It is a directed multigraph parametrized with dictionaries both on nodes and on links. My angular components are working on this complex data model.

In Angular2.4, everything worked fine. Since we switched to Angular4, I get this into my DOM:

<g flareNode="" ng-reflect-model="{'id':'an-id-of-my-object'">

...which is generated from the following template snippet:

<svg:g flareNode [model]="item"></svg:g>

Note, model is here simply a data member of my component. It has no (...should have no) specific Angular2 meaning. It is a part of the complex data structure behind my app.

My first impression is that Angular serializes the model data member of the component class, gets its 30 first characters, and then puts this totally useless thingy into the DOM!

Am I right? What is this whole ng-reflect-model in the DOM, what specific purpose has it in Angular4 what it didn't have in Angular2?

Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
peterh
  • 11,875
  • 18
  • 85
  • 108
  • 4
    Note: this is *not* a debug question, I gave here far not enough info for that. The focus of the question, what the `ng-reflect-model` attribute is for, and maybe that what could be the reason of this strange behavior (putting the first 30 characters of an object into the DOM as the value of an attribute). Any answer explaining what is the role of the `ng-reflect-model` inside the Angular framework is already acceptable. – peterh Apr 13 '17 at 16:56
  • 1
    I can't see `ng-reflect` attributes added to my components, but they were added in 2.4. If you create a plunker with DOM with such attributes, I'll take a look – Max Koretskyi Apr 14 '17 at 06:00
  • @Maximus Yes, in my case ng-reflect- is there in 4.0, but it wasn't in 2. Creating a plunker would be unpractical (it is a big, strongly dependent code, extracting a small part of it would be unfeasible). Anyways, what I want here, is not debug help, instead a better understand, what this ng-reflect thing is for, and that do I see it really well, that angular components behave differently on the first 30 chars of their serialized model variables. – peterh Apr 14 '17 at 11:57
  • I'm not asking you to create a plunker of your entire app, just a demo of a component where `ng-reflect` is used. IMHO, there is no one on stackoverflow who can answer that question right now. I'm interesting to make some debugging and find the answer, as [I write in-depth articles](https://hackernoon.com/everything-you-need-to-know-about-change-detection-in-angular-8006c51d206f), but I need a demo. I spent an hour today trying to come up with an example, but couldn't get `ng-reflect` to be added. – Max Koretskyi Apr 14 '17 at 12:42
  • @Maximum Thank you! I've found a relevant post [here](https://github.com/angular/angular/issues/9707). It says, ng-reflect is only for debugging and that it can be switched of by a param to bootstrapModule. Now the problem is that my app still won't work, and it also ignores the said flag. – peterh Apr 18 '17 at 07:24
  • I've figured it out, check my answer – Max Koretskyi Apr 18 '17 at 13:34
  • 1
    @Maximus Your article is very deep and very hardcore. It may be more worthy even as your answer (also which is very worthy). – peterh Apr 18 '17 at 14:13
  • @peterch, thanks for your kind words! I'll even consider changing `I write in-depth articles` into `I write _hardcore_ articles` :))). I'm planning to write much more, so do follow me for more insights. Good luck! – Max Koretskyi Apr 18 '17 at 14:26

2 Answers2

128

ng-reflect-${name} attributes are added for debugging purposes and show the input bindings that a component/directive has declared in its class. So if your component is declared like this:

class AComponent {
  @Input() data;
  @Input() model;
}

the resulting html will be rendered like this:

<a-component ng-reflect-data="..." ng-reflect-model="...">
   ...
<a-component>

They exist only when debugging mode is used - default mode for Angular. To disable them, use

import {enableProdMode} from '@angular/core';

enableProdMode();

inside main.ts file. These attributes are added by this function here:

function debugCheckAndUpdateNode(...): void {
  const changed = (<any>checkAndUpdateNode)(view, nodeDef, argStyle, ...givenValues);
  if (changed) {
    const values = argStyle === ArgumentType.Dynamic ? givenValues[0] : givenValues;
    if (nodeDef.flags & NodeFlags.TypeDirective) {
      const bindingValues: {[key: string]: string} = {};
      for (let i = 0; i < nodeDef.bindings.length; i++) {
        const binding = nodeDef.bindings[i];
        const value = values[i];
        if (binding.flags & BindingFlags.TypeProperty) {
          bindingValues[normalizeDebugBindingName(binding.nonMinifiedName !)] =
              normalizeDebugBindingValue(value); <------------------
        }
      }

    ...

    for (let attr in bindingValues) {
      const value = bindingValues[attr];
      if (value != null) {
        view.renderer.setAttribute(el, attr, value); <-----------------
Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
  • 1
    @yurzui, thanks for your comment, I'm really flattered. It takes time to debug sources and it's always a good feeling when I know someone benefits!. If you're not yet following me [on medium](https://medium.com/@maximus.koretskyi), don't hesitate :) – Max Koretskyi Apr 18 '17 at 13:41
  • @yurzui, yeah, do you write? – Max Koretskyi Apr 18 '17 at 13:46
  • If I pass objects to input properties I get something like: `ng-reflect-model="[object Object]"`. How to get knowledge what object it is? – Sharikov Vladislav Feb 22 '18 at 12:03
  • 1
    @SharikovVladislav, it's `[object Object]` because Angular calls `toString()` on an object. You should know what object it is by inspecting input bindings. – Max Koretskyi Feb 22 '18 at 12:14
  • @AngularInDepth.com yes, its obvious. Of course I can get this from input bindings. Is it possible to get that info through dom? Like in AngularJS.I could do this: `angular.element($0).scope().$ctrl.`. Is it possible to do something like this? – Sharikov Vladislav Feb 22 '18 at 12:16
  • 4
    @SharikovVladislav, you can get instance of the component using `ng.probe` like this `ng.probe($0).componentInstance[inputBindingProperty]` – Max Koretskyi Feb 23 '18 at 06:47
  • Cool! Thank you. I didn't know this. – Sharikov Vladislav Feb 24 '18 at 10:16
  • Is `ng-reflect` a reliable feature? Can I use it in tests? – Majesty Oct 15 '20 at 14:22
  • @LuninRoman it would be better to test against the actual bindings so the unit tests are better aligned with production code. If `ng-reflect-*` is somehow reliable in development but unreliable in production, it's unlikely that unit tests would pick this up. – Bucket May 05 '21 at 15:21
0

ng-reflect- attributes are all debug helpers to let devtools know what bindings are, which never exist in non-debug (production) mode.

Achraf Farouky
  • 813
  • 10
  • 11