Двусторонняя привязка данных Angular2

Я знаю, что Angular2 не имеет двусторонней привязки данных, но есть ли способ имитировать поведение двусторонней привязки данных из Angular1.x?


person Ronald Wildenberg    schedule 26.05.2015    source источник
comment
Причина, по которой двусторонняя привязка данных была устранена, заключается в том, что это принципиально ошибочная архитектура, поэтому да, вы можете это сделать, но не хотите этого делать.   -  person unobf    schedule 26.05.2015
comment
Что-то о циклах и производительности? Но предположим, мне нужно это для особого случая, как бы я это сделал?   -  person Ronald Wildenberg    schedule 26.05.2015
comment
У меня есть метка где-то на странице и текстовое поле, которое позволяет изменить метку. Если я наберу текстовое поле, метка должна измениться. Если подумать, это не совсем двусторонняя связь... Но я до сих пор не знаю, как это реализовать...   -  person Ronald Wildenberg    schedule 27.05.2015


Ответы (8)


Примечание. Прокрутите вниз ответ для привязки ng-модели

На самом деле вы можете это сделать, просто вам нужно вызвать внутренний тик прослушивателя изменений (аналогичный дайджесту), чтобы обновить привязку в зоне. Вы можете просто добавить для этого событие (keyup). Точно так же вы можете использовать привязки директив с properties словарем настроек компонента.

Пример:-

<input #label (keyup)> 
<!-- variable #label represented as the element itself and accessible as property on controller instance 
 You can even bind keyup to a function or another another function and pass value from the label property-->

Отображать как:

<p>{{label.value}}</P>

Родительский компонент имеет текстовое поле и метку.

import { Component, bootstrap} from '@angular/core';
import {Display} from 'display';

@Component({
  selector: 'my-app',
  template: `<p><b>Parent Component:</b><p><input #label (keyup) (change)="handleChange(label.value)">
        <p>{{label.value}}</P> <display [text]="label"></display></p></p>`,
  directives: [Display]
})

class MainComponent {
  label: any;

  constructor() {

  }

  handleChange(label){
    this.label = label;
    console.log(this.label);
  }

}

Теперь отображаем его и в дочернем компоненте:

@Component({
  selector: 'edit',
  template: `<p><b>Child Component:</b></p>{{text.value}}`
})

export class Edit {
    @Input() text:any;
}

Демо



Обновление — ng-модель для двусторонней привязки

Хотя Angular2 по умолчанию имеет однократную привязку, для достижения двусторонней привязки был введен сахар ngModel. С этим вы могли бы сделать, например:

<input ngControl="name" [(ngModel)]="name">

Здесь использование квадратных скобок ([..]) предполагает привязку свойства и круглых скобок ((..)) для привязки события. По сути, когда вы используете ng-model, вы включаете обе привязки ngModel, это скорее событие. За кулисами он создает наблюдаемое событие (с EventEmitter) для отслеживания value изменений в связанном элементе и обновления связанного свойства соответственно. Например:-

Включить директивы формы:

 import {FORM_DIRECTIVES} from '@angular/common';

и с формой

   <form (ngSubmit)="onSubmit()" let-f="form">
      <input ngControl="name" [(ngModel)]="name">
      <button>Click me and check console</button>
   </form>

без формы

  <input  [(ngModel)]="name">
  <button (click)="onSubmit()">Click me and check console</button>

больше не нужно включать зависимость formDirectives в аннотацию представления.

@Component({
  template: .....,
  directives: [FORM_DIRECTIVES]
})

Демо

Также прочитайте отличную запись от Виктора Савкина о двусторонней привязке в angular2, создав ng событие модели и как оно работает.

person PSL    schedule 27.05.2015
comment
Для более нового Angular (например, v5) вам необходимо импортировать FormsModule. - person zed; 02.04.2018
comment
URL обновления поста Виктора Савкина: vsavkin.com/angular-2-template-syntax-5f2ee9f13c6a - person BlackICE; 06.08.2018
comment
Я думаю, что имя селектора дочернего компонента должно быть «отображение». - person Alessandro_russo; 15.02.2021

Теперь вы можете просто сделать это с помощью ngModel, используя следующий синтаксис:

<input [(ngModel)]="myProp" />

Сочетание квадратных и круглых скобок означает «двустороннюю привязку».

См. планк здесь

person JDTLH9    schedule 25.05.2016

Да, в angular2 есть двусторонняя привязка. См. здесь: https://angular.io/docs/ts/latest/guide/template-syntax.html#!#ngModel

Итак, как использовать его в пользовательских компонентах?

Что мне нравится делать, так это:

private currentSelectedItem: MachineItem;
@Output() selectedItemChange: EventEmitter<MachineItem> = new EventEmitter<MachineItem>();

@Input() set selectedItem(machineItem: MachineItem) {
    this.currentSelectedItem = machineItem;
    this.selectedItemChange.emit(machineItem); 
}

get selectedItem(): MachineItem {
    return this.currentSelectedItem; 
}

И используйте его как

<admin-item-list [(selectedItem)]="selectedItem"></admin-item-list>

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

person Mario Eis    schedule 09.10.2016
comment
это самый разумный ответ, который я нашел для этой проблемы до сих пор, но, к сожалению, я не могу установить начальное значение для этого (если для начала был selectedItem), selectedItem не установлен - person Tolga E; 03.05.2017
comment
Не знаю, правильно ли я понял проблему, но не могли бы вы установить currentSelectedItem (событие не будет сгенерировано) или установить selectedItem в ctor? - person Mario Eis; 03.05.2017
comment
Я пробовал это раньше, и, к сожалению, событие действительно генерируется, поэтому вы застреваете в бесконечном цикле. - person Tolga E; 03.05.2017
comment
currentSelectedItem=xyz инициировал событие? - person Mario Eis; 04.05.2017
comment
Обратите внимание, что имя выходного эмиттера важно. Для этого должно быть выбрано «selectedItemChange». Правило состоит в том, что если ваш ввод «x», выходной эмиттер должен называться «xChange», чтобы банан в синтаксисе коробки работал. Я ломал голову над этим, пока не увидел эту статью, в которой упоминался этот факт. bytes.vokal.io/20160509-angular-data-binding - person Yohan Liyanage; 10.05.2017
comment
Да, точно. Это то, что официально описано в документах Angular (см. ссылку, которую я предоставил) в разделе Inside [(ngModel)] - person Mario Eis; 12.05.2017

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

http://plnkr.co/edit/lOFzuWtUMq1hCnrm9tGA?p=preview

Создайте компонент с внутренним атрибутом, содержащим метку this.label, и обратный вызов changeLabel, который ожидает объект события.

@Component({
  selector: 'app',
  templateUrl: 'bound.html'
})
class App {
  label: string;
  constructor() {
    this.label = 'default label'
  }
  changeLabel(event) {
    this.label = event.target.value;
  }
}

bootstrap(App);

Создайте свой шаблон и прикрепите обратный вызов к соответствующему событию (вы можете прикрепить его к событию keypress, но тогда вам может понадобиться тайм-аут. Я прикрепил его к событию change для простоты (это означает, что вам может потребоваться отложить ввод для смотрите обновление).

<label for="myinput">{{label}}</label>
<input id="myinput" type="text"/>
<p></p>You can change the label above by typing something below</p>
<label for="labeltext">New Label Text</label>
<input type="text" id="labeltext" (change)="changeLabel($event)"/>
person unobf    schedule 26.05.2015

Есть еще один способ заставить Angular2 использовать двустороннюю привязку. Не передавайте свойство, а объект в компонент. Если вы передаете объект через одностороннюю привязку, все его свойства на самом деле являются двусторонними. Это делает компонент менее универсальным, поскольку ему необходимо знать объект, но во многих случаях он все еще полезен.

У меня есть компонент, который выглядит так:

import { Component, Input }    from "@angular/core";
import { NgSwitch, NgSwitchWhen, NgSwitchDefault }    from "@angular/common";

export class Movie
{
    public Title: string;
    public Rating: number;
    public Seen: boolean;
}

@Component
({
    selector: "hh-image-checkbox",
    template: `
        <div [ngSwitch]="movie.Seen"> 
            <div *ngSwitchWhen="true">
                <img src="/Content/res/CheckTrue.png" (click)="onClick()"> 
            </div> 
            <div *ngSwitchDefault> 
                <img src="/Content/res/CheckFalse.png" (click)="onClick()"> 
            </div> 
        </div>
        `,
    directives: [NgSwitch, NgSwitchWhen, NgSwitchDefault]
})

export class ImageCheckboxComponent
{
    @Input() movie: Movie;

    public onClick()
    {
        this.movie.Seen = !this.movie.Seen;
    }
}

Вызывается так:

<hh-image-checkbox [movie]="movie"></hh-image-checkbox>

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

person hholtij    schedule 13.06.2016
comment
Не нужно импортировать NgSwitch, NgSwitchWhen, NgSwitchDefault and add them to directives. They are provided globally by PLATFORM_DIRECTIVES` - person Günter Zöchbauer; 13.06.2016

Вот простой планкер, который демонстрирует односторонний, двусторонний и событийный подходы в действии в соответствии с Angular2 2.0.0-beta.17.

http://plnkr.co/eXZMoU

Двустороннее событие и собственность

<input [(ngModel)]="name" />

Односторонняя собственность

<input [value]="name" />

События

<input (input)="name=$event.target.value">

Мы можем найти больше

[ОБНОВЛЕНИЕ 26.01.2020]

Поскольку бета-библиотеки Angular2 удалены из CDN проекта! ссылка выше plnkr больше не работает.

Используйте ниже новую страницу plnkr Angular 6+, я перенес предыдущую страницу в NPMJS, новую версию angular и новый plnkr!

http://next.plnkr.co/edit/4okdOSgw3SMvdktR?preview

person Davut Gürbüz    schedule 09.11.2016

Из документов:

Двусторонняя привязка ( [(...)] )

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

На стороне элемента требуется комбинация установки определенного свойства элемента и прослушивания события изменения элемента.

Angular предлагает для этой цели специальный синтаксис двусторонней привязки данных, [(x)]. Синтаксис [(x)] объединяет скобки привязки свойства [x] со скобками привязки события (x).

[( )] = BANANA IN A BOX

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

Для получения дополнительной информации см.

person georgeawg    schedule 05.03.2019

Это просто, попробуйте это;

<input [(ngModel)]="property" placeholder="property Value"/>
<h1>{{property}}</h1>
person Jalasem    schedule 17.06.2016