Angular 2 - pass an object field by reference. Reusable way to edit objects

▼魔方 西西 提交于 2021-01-28 01:12:30

问题


I am creating reusable table component which will enable editing of objects fields to prepare them for sending to the API.

Having an object:

person: {
  name: "John"
  job: {
    type: "IT"
    title: "Software Engineer"
  }
}

I would like to pass the object nested field to a component and edit. F.e:

<edit-field [field]="person.job.title"></edit-field>

Which results in an input field that edits exactly the title field in original object. The problem is that person.job.title is a string, not and object or array so it's not passed by reference.

I had 2 ideas haw the problem could be solved: 1) pass "person.job.title" as a string:

<edit-field [field]="'person.job.title'"></edit-field>

or

<edit-field field="person.job.title"></edit-field>

And in component class do split by a ".":

let fields = this.field.split('.');

and then do a while loop to access the field by reference.

We could also do 2 inputs:

<edit-field-component [fieldRef]="person.job" [field]="'title'"></edit-field-component>

and then inside component do this.fieldRef[this.field]

I am wondering if there is any other, more clean, way to achieve that.


回答1:


Basically, you want to accomplish two-way binding - i.e. changes to the object value: eg person.job.title updates your new edit component, but also changes made from your edit component also get reflected back to the object value.

In Angular, that means you have to bind both ways:

<edit-field [field]="person.job.title"  (change)="person.job.title=$event"></edit-field>

where your edit-field component has an @Output property that emits the changed value whenever someone types into it. The value emitted from the @Output property will be in the variable $event and you simply want to assign that back to the property that you want to update.

So, your EditFieldComponent can look something like:

@Component({
   .....
   template: `
      <input (input)="change.emit($event.target.value)" ....   />
   `
})
export class EditFieldComponent {
   change = new EventEmitter();
}

The above means that whenever an input event triggers on your input field, the component's change output property will emit the new value of the input field.

===========

If you understand everything above, then Angular provides a little shortcut for this exact scenario. If the output property of your component is named a specific way, you can simplify how you write the two way binding.

So, if your input property is field, and you name your output property fieldChange you can make use of some fancy syntax to cut down how much you have to type.

i.e.

<edit-field [field]="person.job.title"  (fieldChange)="person.job.title=$event"></edit-field>

is equivalent to:

<edit-field [(field)]="person.job.title"></edit-field>



回答2:


[field]="person.job.title" is one-way binding (changes of person.job.title are propagated to field but not the other way round)

[(field)]="person.job.title" would achieve two-way binding (changes made by fieldChange method are also propagated back to person.job.title)




回答3:


If you want to reffer your object or property of your object to your component, you need to create an @Output property with type eventEmitter.

@Input('field') field: any;
@Output() fieldChange = new EventEmitter();

Be carefull to name your output property with "Change" suffix word. It will detect automatically change from your object and notify to your main object.




回答4:


Javascript just like Java is passed by value, they have never offered passed by reference. So in your case, your best option is to pass your person object directly. Even though it will be copied inside your function, the copy still refers to the same object, so changing a field in the copy will also change the corresponding field in the original.



来源:https://stackoverflow.com/questions/43570075/angular-2-pass-an-object-field-by-reference-reusable-way-to-edit-objects

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!