1

I have been working in angular( version 5.2 ) for a couple of months now and feel as though I must be missing something fairly obvious. My problem is that I need to perform manipulation to my data between the view and the model.

For example I am building a simplified app that interacts with Microsoft project. The end user should only have to enter a start and end date for each task. Depending on a few other factors that exist within my component it may update the models start/end date directly( +- extra days) or alter another variable within that task. So using

<input type="date" [(task.startDate)] />

isn't really appropriate. My solution to this is was to use something like

<input type="date" (change)="processTheDate($event.value, task)" [value]="task.startDate" >


private processTheDate(value: Date, task: Task){

     //do some proccessing

     //set the value
     task.startDate = value;
}

From what I have read online this is not the preferred solution

My questions is actually two fold.

1. What is wrong with usurping angular's data binding such as in my example?

2. What is a better alternative?

  • I should also point out that my example is very simplified, and used to explain my problem. This is a problem that has occured quite a few times whilst developing in angular. – user1326240 Mar 07 '18 at 07:29

2 Answers2

2
  1. Nothing is inherently wrong (except calling a private method from the view). But most of the time, a form is used to gather information, and then do something with it when it's submitted. So simply binding the form controls to a model makes sense.

  2. There are several alternatives:

    • You can use a template-based form (i.e. ngModel), and, in addition to simply binding the field to task.startDate, use (ngModelChange) to react to the model change, and thus process the date. Or you can use a setter instead of a public field, and thus do the work from inside the setter
    • You can use a reactive form, and subscribe to the valueChanges observable of the FormControl to be notified every time the value changes, and thus process the date from there.
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Thanks for the answer, glad to see i'm not doing anything to strange. I did play with reactive forms a little, but i found them a little complicated and inflexible( This was when i was just beginning so I might revisit them) . – user1326240 Mar 07 '18 at 08:46
  • Also whats wrong with accessing a private method from view? It works fine, and so i assumed that the view was kind of like a member of the component, and so allowed to acces it. – user1326240 Mar 07 '18 at 08:48
  • It works fine in JIT mode. As soon as you'll build for production, with the --prod flag (or just the -aot flag), it won't anymore. The view is a client of the component: it accesses its fields. The AOT compiler compiles the view to a TypeScript class. A TypeScript class may not access a private field of another class. – JB Nizet Mar 07 '18 at 17:00
  • Ahhh yes that would make sense. I think I may need to reconfigure a few things to get a working production build. How much faster is aot compared to jit, I have been running live tests( without prod) and have had pretty good load times so far. – user1326240 Mar 07 '18 at 20:06
  • The runtime is just as fast. What changed dramatically is the startup time: Angular doesn't have to compile all the component templates anymore, and the compiler doesn't have to be bundled anymore. When you start having something like 50 or 100 components (which is not that much), you can see a real difference (a few millis vs. 2-4 seconds). Why don't you use angular cli? All you would have to do is `ng build --prod`. – JB Nizet Mar 07 '18 at 20:11
  • 1
    I have angular directly integrated into my backend( MVC 5) and the whole lot goes up at once. This is starting to look like a bad way of doing things, so I may need to restructure, the angular part to its own project>> build using prod>> insert static files into the MVC backend – user1326240 Mar 07 '18 at 20:21
0

I don't see anything wrong with your solution.

I think using ngModel is usually better for two-way binding because you don't have to write the code that sync the values multiple times. However if you need to perform a lot of logic when the value updates, it's perfectly ok to use change.

You can also mix them, in case you want to keep the two-way binding while doing some logic when the value changes.

<input type="date" (change)="onStartDateChange($event.value, task)" 
       [(ngModel)]="task.startDate" >

onStartDateChange(value: Date, task: Task){

     //do some proccessing

     //set the value
     task.startDate = value;
}
Naoe
  • 1,209
  • 8
  • 12
  • Thanks for replying. Like JB Nizet's answer the two way binding and change event probably is a bit neater. Any ideas if it's better performance wise, seeing as it's done with one binding? – user1326240 Mar 07 '18 at 08:53
  • I think that performance wise they are very similar. ngModel is optimized for two-way binding, but supports alot of different scenarios. If you want to take a deep dive, you can read the source code of ngModel here: https://github.com/angular/angular/blob/5.2.7/packages/forms/src/directives/ng_model.ts#L47-L273. – Naoe Mar 07 '18 at 09:22
  • I agree, they seemed pretty similar in my experience. – user1326240 Mar 07 '18 at 09:30