23

I'm making an Angular 2 web app. I have a model that is comprised of a few key properties, and then several other properties that are computed based off those key values.

All of my properties have getter methods. To keep my computed properties in sync with my key properties, the key properties are changed via setter methods which re-evaluate all of the computed properties. Here's a simplified example:

export class Model{ private _keyValue: number; private _computedValue: number; getKeyValue(): number{ return this._keyValue; } setKeyValue(value: number){ this._keyValue = value; this.evaluateComputedValues(); // This might be time-consuming } getComputedValue(): number{ return this._computedValue; } } 

This keeps my model consistent: every time one of the key properties is changed, all of the computed properties are re-computed.

Now I need to figure out how to bind my properties to my component views. It seems like I can present the computed property getters using interpolation:

<div>{{model.getComputedValue()}}</div> 

However, I'm not sure what the best way to bind my key properties to input fields would be. All of the examples of using two-way binding seem to use ngModel like this:

<input [(ngModel)]='model.property'> 

However, that seems geared towards binding to simple properties. I ideally need two-way binding using my separate getter and setter methods (getKeyValue and setKeyValue).

Is there any built-in way to accomplish this in Angular 2?

3
  • 4
    Why don't you use TypeScript getters and setters instead of functions? You get the same functionality but can use them as if they were fields. See also stackoverflow.com/questions/12827266/get-and-set-in-typescript Commented Oct 31, 2016 at 11:59
  • @Günter Zöchbauer If I went that route, would binding the property like this [(ngModel)]='keyValue()' work? Will Angular 2 figure out when to use the getter and the setter? Commented Oct 31, 2016 at 12:24
  • 3
    Almost. It would look like [(ngModel)]='keyValue'. For such getters/setters you don't need (). Commented Oct 31, 2016 at 12:26

2 Answers 2

36

You need to use this longer form

<input [ngModel]='model.getProperty()' (ngModelChange)="model.setProperty($event)"> 

You should be aware that the getXxx() methods will be called every time change detection runs, which can be quite often. Ensure that the getters return the same value (especially for objects the same instance) and ensure the getters don't have side effects, otherwise you'll get "Expression has changed since it was last checked ..." errors.

Sign up to request clarification or add additional context in comments.

6 Comments

I'm curious, as you say, the get method will be called every time change detection runs. This will also apply when using typescript getters, no? Would it have an huge impact performance wise? I guess not, if you really just return the value or only do minor processing, right?
If the method doesn't do actual (expensive) work it's not too bad. It's error-prone if the getter/method returns an object like return { x: y }; because this way a different object instance is returned which breaks change detection.
True, as you said, one has to be careful. Therefore I can understand why it is discouraged. But on the other hand, e.g. when dealing with awkward REST APIs, getters and setters are the way to go, because you might do some conversion at one single place, the model, and not all components using this model.
If you do conversions you should consider pipes. For asyn results bind to observables isimg | async otherwise assign the result to a field and bind to that field. A getter tjat actually does some work shoild be avoided.
Question, there is no way you could use [(ngModel)]='someValue, right? Because that would mean you would have to provide a Change function, but I have no clue as how to name that change function so it would be called on input change. It's def not going to be ngModelChange, right? I was looking at the example at https://angular.io/guide/template-syntax#two-way-binding--- but this doesn't use an input with ngModel.
|
10

not sure what version of Angular is being used above, but the version I'm using (v4.3.5) allows binding directly to the getter/setter methods of a field using ngModel: in the typescript file:

 get AnnualRevenueFormatted():string{ return this.AnnualRevenue !== undefined ? `$${this.AnnualRevenue.toLocaleString()}`: '$0'; } // strip out all the currency information and apply to Annual Revenue set AnnualRevenueFormatted(val: string) { const revenueVal = val.replace(/[^\d]/g, ''); this.AnnualRevenue = parseInt(revenueVal); } 

and in the template file

<input type="text" class="text-input" [(ngModel)]="accountInfo.AnnualRevenueFormatted" /> 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.