Оновіть властивість батьківського компонента з дочірнього компонента в Angular 2


80

Я використовую @inputдля отримання властивості від батьківського компонента, щоб активувати клас CSS в одному з елементів дочірнього компонента.

Я можу отримати властивість від батьків, а також активувати клас. Але це працює лише один раз. Властивість, яку я отримую від батьків, - це логічні дані, що вводяться, і коли я встановлюю статус цього falseз дочірнього компонента, це не змінюється в батьківському.

Plunkr: https://plnkr.co/edit/58xuZ1uzvToPhPtOING2?p=preview

app.ts

import {Component, NgModule} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import { HeaderComponent } from './header';
import { SearchComponent } from './header/search';

@Component({
  selector: 'my-app',
  template: `
    <app-header></app-header>
  `,
})
export class App {
  name:string;
  constructor() {
  }
}

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App, HeaderComponent, SearchComponent ],
  bootstrap: [ App ]
})
export class AppModule {}

header.ts

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-header',
  template: `<header>
              <app-search [getSearchStatus]="isSearchActive"></app-search>
              <button (click)="handleSearch()">Open Search</button>
            </header>`
})
export class HeaderComponent implements OnInit {
  isSearchActive = false;

  handleSearch() {
    this.isSearchActive = true
    console.log(this.isSearchActive)
  }

  constructor() { }
  ngOnInit() { }
}

заголовок / search.ts

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'app-search',
  template: `<div id="search" [class.toggled]="getSearchStatus">
              search 
              <button  (click)="getSearchStatus = false" class="close">Close Search</button>
            </div>`
})
export class SearchComponent implements OnInit {
  @Input() getSearchStatus: boolean;

  constructor() { }

  ngOnInit() {

  }
}

Будь ласка, перевірте наведений вище плюнкер. Функція відкритого пошуку працює лише один раз. Після закриття пошуку він не запускається знову.

Чи @inputє правильним варіантом використання цього сценарію? Будь ласка, допоможіть мені це виправити. (Будь ласка, оновіть програвач).


Де ви встановите `this.isSearchActive = брехня;` після того, як він був встановлений trueв handleSearch()?
Günter Zöchbauer

у заголовку / search.ts '<button (click) = "getSearchStatus = false" class = "close">'
Body

Відповіді:


137

Вам потрібно використовувати двосторонній прив'язок даних.

@Input()є одним із способів прив’язки даних. щоб увімкнути двосторонню прив'язку даних, вам потрібно додати @Output()відповідну властивість із суфіксом "Змінити"

@Input() getSearchStatus: boolean;
@Output() getSearchStatusChange = new EventEmitter<boolean>();

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

this.getSearchStatusChange.emit(newValue)

а в батьківському для цього властивості потрібно використовувати позначення banana-in-a-box:

[(getSearchStatus)]="myBoundProperty"

Ви також можете прив’язати до властивості та викликати зворотний виклик, коли він змінюється у дочірньому:

[getSearchStatus]="myBoundProperty" (getSearchStatusChange)="myCrazyCallback($event)"

див. plnkr


Дякую за відповідь. Чи можете ви оновити мою програму?
Body

1
Це додасть додаткової роботи для тієї самої поведінки, що і використання @Output(). Це звучить як переобладнання колеса. @RobertVangor
n00dl3

2
Використовуючи ReactiveForms, навіть з позначеною властивістю дочірнього publicпристрою, я не міг використовувати підхід "банановий ящик" і отримав помилки, оскільки це не було відомою властивістю компонента ... (propertyChanged)="setParentProp($event)"Хоча прив'язка лише до спрацьованого ідеально.
mc01

1
Я не можу відповісти на ваше запитання, оскільки воно заслуговує власного допису. Ваша проблема полягає в тому, що ви випускаєте зміни відразу після циклу виявлення змін батьками. Іншими словами, вам вдалося здійснити виявлення змін, щоб викликати деякі зміни, які не дозволено Angular. @manoj
n00dl3

2
@Chandrakant ні, для використання синтаксису бананових коробок потрібно використовувати суфікс зміни. Для користувацьких результатів ви можете назвати його як завгодно. Бананова коробка тільки дуже дурний синтаксис , який зловживає багато людей
Allwe

7

Інший підхід: використовуйте rxjs / BehaviourSubject для передачі статусу між різними компонентами.
Ось plunkr .
Я називаю тему з суфіксом 'Rxx', тому BehaviourSubject для searchStatus буде searchStatusRxx.

  1. ініціалізувати його в батьківському компоненті, наприклад searchStatusRxx = new BehaviorSubject(false);,
  2. передайте його дочірньому компоненту за допомогою @Input
  3. у дочірньому шаблоні ви робите асинхронну трубу.
  4. як для батьків, так і для дітей, ви searchStatusRxx.next(value)хочете змінити останнє значення.

4

Трохи відредагував ваш код, він працює і виглядає простіше imo. Скажи мені, чи тобі це подобається.

https://plnkr.co/edit/oJOjEZfAfx8iKZmzB3NY?p=preview


Дякую. я хочу оновити батьківську властивість з компонента пошуку. Це мій варіант використання.
Body

@Body Fine, але вам слід задуматися про те, як я змінив ваші кнопки та механізм натискання, разом із рішенням n00dl3.
добрий користувач

2

Ще інший шлях. Плункр . Ми хочемо єдиного джерела істини. Цього разу ми можемо вкласти це в дитину.

  • Ініціація у дитини: searchStatus = false
  • У батьківському шаблоні отримайте екземпляр дочірнього #asімені або будь-якого іншого імені.
  • Змінити статус пошуку в батьківському, що використовує, #as.searchStatusта в дочірньому this.searchStatus.

Цей спосіб набагато кращий і простіший. Чи це дійсний спосіб продовжити? Чому Angular не просуває цей метод? Я шукаю рішення з тижня, і скрізь я знаходив випадки введення / виводу.
Body

Давайте назвемо це способом "Шаблон посилальних змінних". Здається, це просто. Але це може бути трохи складніше протестувати, і батьківський / дочірній компоненти з'єднуються, що може бути не дуже добре. Особисто я віддаю перевагу способу BehaviourSubject, який простіше перевірити та розв’язати і може бути встановлений як властивість складного об’єкта, що проходить між батьком та дочірнім об’єктом. Сиденот: angular's eventEmitter - це тема за кадром.
Тіматон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.