0

I have this component:

@Component({
    selector: 'child'
})
export class ChildComponent {
    @Input() childObject: ChildObject;

    changeObject(newObject: ChildObject){
        childObject = newObject;
    }
}

When I call changeObject, my ChildComponent reflect the changes, but my ParentComponent, which contains the ChildComponent, isn't updated with this change.

I.e.: If, in my ParentComponent template I have something like {{parent.childObject.name}}, this value stay unchanged.

I tried to use childObject = JSON.parse(JSON.stringify(newObject)); but it doesn't help. I guess it's a problem of object reference changing, so I added a method copy(newObject: ChildObject) that makes a copy property-by-property in my ChildObject class, but when I call it in my changeObject method, I get this error:

ERROR TypeError: _this.childObject.copy is not a function.

Update: ChildObject class

export class ChildObject {
  constructor(
    public name: string // , ...
  ) { }

  copy(childObject: ChildObject) {
    this.name = childObject.name;
    // ...
  }
}
2
  • You need to emit the changes back to parent - @Input() properties doesn't carry the reference Commented Nov 12, 2018 at 9:59
  • @input works the other way try @output instead. Commented Nov 12, 2018 at 10:04

3 Answers 3

2

this will not work, you should use here service or @Output, I would suggest to use @Output here if there will be only this communication between your components

@Component({
    selector: 'child'
})
export class ChildComponent {
    @Input() childObject: ChildObject;
    @Output() onChildObjectChange = new EventEmitter<ChildObject>();
    changeObject(newObject: ChildObject){
        childObject = newObject;
        this.onChildObjectChange.emit(newObject);
    }
}

Parent component Html

<child (onChildObjectChange)="updateObject($event)"></child>

ts

updateObject(newObject: ChildObject) {
  childObject = newObject
}
Sign up to request clarification or add additional context in comments.

7 Comments

Hum... seems quite complex for something that should be automatic. In that case, I'd rather investigate my copy(newObject: ChildObject) solution in the ChildObject class that makes a property by property update. But I can't make out why I get this not a function error...
@Sébastien this is one of possible solutions, you can also use services, also can you provide code where you are getting not a function error so we can help in that case too
My ChildObject class is a quite simple model class, I updated my question with this class.
@sebastian when you are passing childObject from parent to child does it has the copy method? I would suggest to use services instead of that class
Isn't the method set at class level?
|
1

EDIT: A direct assignment will not work because it replaces original object reference with the new one

this.childObject = newObject; // Will not work

However, any update on an existing object should work

this.childObject.someProperty = newObject; // should work

Object.assign(this.childObject, newObject);  // should work since it will assign the merge to the first object

Should work since objects are passed as a reference while passing inputs. The only problem I see in the code you have posted is you should refer to the childObject as this.childObject

@Component({
    selector: 'child'
})
export class ChildComponent {
    @Input() childObject: ChildObject;

    changeObject(newObject: ChildObject){
        this.childObject = newObject;
    }
}

This should work. Although I would not do it this way. This can be done in a cleaner way.

10 Comments

I just forgot this while typing my exemple, but it is in place in my accual code and no it doesn't work. Why do you think it isn't a clean way? It looks to me quite simple and maintainable.
'@Input' should be used to pass data from parent to child and not the other way around. If you want to pass data from child to parent component, you should use '@Output', ValueAccessor or service. I do not recommend using service as well but it's an option.
Well, this is only model data for my form, so the changes are always sent back to the parent components. The reason why i have this object copy is that the user can select the ChildObject in a list to auto-complete the form.
Yes, this works. Simple and clean (I guess). Do you know what Object.assign does to refererences type (i.e., if I have other complex objects in ChildObject)? Are the object references copied to the object or is it a recursive copy?
It's a recursive copy. If I have 2 objects obj1 and obj2 and I do Object.assign(obj1, obj2), it will copy all properties from obj2 to obj1 and these copied properties will no longer have reference to obj2. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
|
0

You can possiable get the value changed by adding ChangeDetectionStrategy.OnPush on your child

@Component({
    selector: 'child',
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class ChildComponent {
    @Input() childObject: ChildObject;

    changeObject(newObject: ChildObject){
        childObject = newObject;
    }
}

This will update your object whenever there is any event triggering on your child component the case is that both the child component and parent component changeDetection will occur and thus it will update your object

Hope you're expecting something like this - Happy coding !!

1 Comment

Some event should be triggered to achieve this - if not change it to default ChangeDetectionStrategy.Default which will trigger every time without event change

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.