最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Will using Angular Reactive Forms .get() method in template cause unnecessary method calls like a component method?

programmeradmin0浏览0评论

I know that if I use a method call in a template it will get executed over and over (not ideal). I have solved that by using a combination of pure pipes and memoized methods. But I am also using reactive forms and in my template using the myFormGroup.get('myFormControl').value to get the values. Will this too get executed repeatedly like the method in my component or does Angular have a strategy in place to prevent this? A usage example is using *ngIf and having the conditional be based on a value of the form.

Also, I am not experiencing any performance degradation currently, but I would like to implement this in the best way possible before getting too far down the road with this application (and am just curious).

I can easily update it to reference the properties on the form object directly, I just prefer the syntax of the method call. Any insight would be helpful, thanks!

I know that if I use a method call in a template it will get executed over and over (not ideal). I have solved that by using a combination of pure pipes and memoized methods. But I am also using reactive forms and in my template using the myFormGroup.get('myFormControl').value to get the values. Will this too get executed repeatedly like the method in my component or does Angular have a strategy in place to prevent this? A usage example is using *ngIf and having the conditional be based on a value of the form.

Also, I am not experiencing any performance degradation currently, but I would like to implement this in the best way possible before getting too far down the road with this application (and am just curious).

I can easily update it to reference the properties on the form object directly, I just prefer the syntax of the method call. Any insight would be helpful, thanks!

Share Improve this question asked May 26, 2020 at 23:44 MrUnderhillMrUnderhill 1731 gold badge1 silver badge5 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 16

This is what happens when you call AbstractControl.get(...):

get(path: Array<string|number>|string): AbstractControl|null {
  return _find(this, path, '.');
}

Source.

And the _find function looks like this:

function _find(control: AbstractControl, path: Array<string|number>|string, delimiter: string) {
  if (path == null) return null;

  if (!Array.isArray(path)) {
    path = path.split(delimiter);
  }
  if (Array.isArray(path) && path.length === 0) return null;

  // Not using Array.reduce here due to a Chrome 80 bug
  // https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
  let controlToFind: AbstractControl|null = control;
  path.forEach((name: string|number) => {
    if (controlToFind instanceof FormGroup) {
      controlToFind = controlToFind.controls.hasOwnProperty(name as string) ?
          controlToFind.controls[name] :
          null;
    } else if (controlToFind instanceof FormArray) {
      controlToFind = controlToFind.at(<number>name) || null;
    } else {
      controlToFind = null;
    }
  });
  return controlToFind;
}

Source.

As you noticed, you can get descendants that reside deeper in the form control tree.

For instance:

form.get('a.b.c')

// Or

form.get(['a', 'b', 'c'])

This whole logic involes an iteration, because it's iterating over each element from path.


Will this too get executed repeatedly like the method in my component

I'd say it will.

I've created a StackBlitz demo to illustrate this:

@Component({
  selector: 'my-app',
  template: `
    <form [formGroup]="form">
      <input formControlName="name" type="text">  
    </form>

    <hr>

    <p>
      Getter value: {{ name.value }}
    </p>
  `,
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  form: FormGroup;
  name2: FormControl

  get name (): FormControl {
    console.log('getter invoked!')

    return this.form.get('name') as FormControl;
  }

  constructor (private fb: FormBuilder) { }

  ngOnInit () {
    this.form = this.fb.group({ name: '' });

    this.name2 = this.form.get('name') as FormControl;
  }
}

If you're using a getter, you should see getter invoked! logged twice for each character you type in the input(and the get method called multiple times as well).

If you're using {{ form.get('name').value }}, the AbstractControl.get method will be called multiple times, more than expected.

You can test this by opening the dev tools, typing forms.umd.js and placing a log breakpoint at this line path.forEach(function (name) {...}, inside _find function's body.

And if you're using this.name2 = this.form.get('name') as FormControl;, you should see nothing logged as you're typing.

In my opinion, it's less likely that the visible performance will decrease if you're using a getter or .get(), but I'd go with the third approach, creating a separate property for the control I'll be using in the view.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论