Дает ли @Input двухстороннее связывание? - PullRequest
0 голосов
/ 08 ноября 2018

То, как я думал, @Input работает, прямо скажет "Нет!" на этот вопрос. Однако сегодня я натолкнулся на какое-то странное поведение, или, может быть, я всегда думал неправильно о @Input ..

Я сделал stackblitz , чтобы показать проблему. Это происходит в stackblitz для Angular 7.0.1, но в моем локальном проекте это также происходит в Angular 6.1.2.

Stabblitz показывает простой родительский компонент, который имеет объект. Объект передается дочернему компоненту через @Input. И дочерний, и родительский компонент имеют функцию, которая изменяет объект. Оба они также показывают значение объекта в шаблоне.

Я ожидал увидеть, что когда родитель изменяет объект, он меняет его в дочернем объекте. Однако я не ожидал, что когда дочерний объект изменяет объект, он также меняет его для родительского объекта. Стекблиц действительно показывает это поведение как бы то ни было. Я всегда думал, что вам нужно явно отправлять событие через @Output, чтобы передать поток родительскому элементу и изменить его там из дочернего компонента.

Ответы [ 4 ]

0 голосов
/ 08 ноября 2018

Ответ «нет». В вашем примере значение, которое вы передаете свойству @Input, является ссылкой на объект. Если бы у вас была двусторонняя привязка, вы могли бы назначить новый объект этому свойству в дочернем компоненте:

this.thing = { name: "world", nbm: 10 };

и соответствующее свойство в родительском компоненте будет соответствующим образом обновлено. Это не так, как вы можете видеть в этом стеке бликов .

Однако, поскольку родительский и дочерний компоненты имеют ссылку на один и тот же объект, они оба могут изменять одно из его свойств, и это изменение будет наблюдаться в другом компоненте.

<Ч />

Чтобы реализовать двустороннюю привязку, вы можете добавить свойство @Output с тем же именем, за которым следует Change, и выдать событие, когда произойдет изменение:

@Input() thing: any;
@Output() thingChange = new EventEmitter();

setNewObject(){
  this.thing = { name: "world", nmb: 10 };
  this.thingChange.emit(this.thing);
}

Изменение будет отражено в родительском компоненте, если используется синтаксис двустороннего связывания:

<child2 [(thing)]="thing"></child2>

См. этот стек для демонстрации.

<Ч />

Если вы хотите запретить дочернему компоненту изменять исходный объект, вам следует привязать свойства объекта вместо самого объекта:

@Input() thingName: string;
@Input() thingNmb: number;
<child [thingName]="thing.name" [thingNmb]="thing.nmb"></child>
0 голосов
/ 08 ноября 2018

Двухсторонняя привязка данных представляет собой комбинацию event привязки и property привязки бананового синтаксиса - Где [(ngModel)] - комбинация [ngModel] и (ngModelChange) событий

Вот волшебство со словом Change, когда имя модели, за которым следует слово Change angular, распознает, что это будет двухстороннее связывание данных, и заставит его работать так же

Приход к Child компоненту @Input() - это способ передачи данных дочернему элементу в виде property привязки, тогда как @Output() - тип отключения передачи данных от дочернего элемента к родительскому элементу в виде event привязки. добиться двухстороннего связывания, которое нужно обоим - проверьте пример ниже

getModelList: any[];
    @Output() modelListChange: EventEmitter<any[]> = new EventEmitter<any[]>();
    @Input()
    get modelList(): any[] {
        return this.getModelList;
    }
    set modelList(value) {
        this.getModelList = value;
        this.modelListChange.emit(this.getModelList);
    }

В приведенном выше коде у нас есть свойство modelList и свойство modelListChange с комбинацией обеих привязок, поэтому мы можем получить доступ к свойству modelList как [(modelList)]="value", и это ваше свойство двустороннего связывания

Доступ от родителя - <multi-dropdown [(modelList)]="value"></multi-dropdown> теперь ваше родительское свойство будет обновляться на основе двухсторонней привязки данных - Убедитесь, что вы правильно написали Change, что также чувствительно к регистру

Надеюсь, это поможет вам - Спасибо, Happy coding !!

0 голосов
/ 08 ноября 2018

Да, Angular Change Detection течет от parent до child, однако то, что вы испытываете, не относится к Object reference. Поскольку общий объект в parent и child указывает на один и тот же reference, он будет обновлен в обоих компонентах.

Всякий раз, когда вы вносите какие-либо изменения через дочерний компонент, общий объект также будет изменяться в родительском компоненте, и Angular будет обнаруживать изменения и запускать обновление пользовательского интерфейса.

Однако это не тот случай с примитивным типом данных. То, что вы подумали, верно для примитивного типа данных. Если примитивный тип данных изменяется, он переходит от родительского к дочернему, а не наоборот.

Вот демо для того же самого - https://stackblitz.com/edit/angular-1wusrc

0 голосов
/ 08 ноября 2018

Когда стратегия обнаружения изменений установлена ​​в ChangeDetectionStrategy.Default, angular часто будет запускать обнаружение изменений, и да, это будет работать.

Установите для него значение ChangeDetectionStrategy.OnPush, и вы увидите другое поведение.

Этот параметр настраивается в аннотации компонента:

@Component({
    selector: 'my-awesome-component',
    templateUrl: './my-awesome-component.html',
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyAwesomeComponent{

}

edit: Я только что попытался изменить ChangeDetectionStrategy на OnPush в вашем стеке, и изменения все еще отражаются. Я просто снова прочитал документы, и, по-видимому, причина того, что это всегда обновляется, заключается в том, что событие нажатия на вашей кнопке запускает обнаружение изменений, и обнаружение изменений запускается от дочернего к родительскому. Таким образом, вы могли бы сказать, что обнаружение изменений всплывает до корня, как это происходит в html-событии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...