2016-02-25 16 views
18

In Angular2 (Beta 6) habe ich eine Komponente für ein Hauptmenü.Angular2 - Zwei-Wege-Datenbindung für eine Komponentenvariable/Komponentenklasseneigenschaft?

<mainmenu></mainmenu> 

Ich möchte einen boolean für breit oder schmal binden. Also machte ich es in diese:

<mainmenu [(menuvisible)]="true"></mainmenu> 

Aber was will ich (glaube ich) ist auf eine JavaScript-Klasse Eigenschaft zu binden (wie ich andere Dinge haben zu binden, aber ordentlich sein wollen durch eine einzige Klasse mit in die Komponente).

Ich erhalte einen Fehler

EXCEPTION: Template parse errors: Invalid property name 'menumodel.visible' ("

][(menumodel.visible)]="menumodel.visible">

Wenn ich das gleiches mit einer einzigen Variablen statt einer Klasse versuchen, erhalte ich:

Template parse errors: Parser Error: Unexpected token '='

Doch diese (? Eine Art und Weise bindend) scheint zu funktionieren (aber ich möchte das Menü auslösen, um weit/schmal von einer anderen Komponente zu gehen, so dass dies eine bidirektionale Datengebundene Eigenschaft sein sollte):

<menu [vis]="true"></menu> 
Diese

ist ein bisschen meine Menükomponente:

@Component({ 
    selector: 'menu', 
    templateUrl: './app/menu.html', 
    providers: [HTTP_PROVIDERS, ApplicationService], 
    directives: [ROUTER_DIRECTIVES, FORM_DIRECTIVES, NgClass, NgForm] 
}) 
export class MenuComponent implements OnInit { 

    mainmenu: MainMenuVM; 

    constructor(private _applicationService: ApplicationService) { 
     this.mainmenu = new MainMenuVM(); 
    } 

    // ...ngOnInit, various functions 

} 

Hier ist meine MainMenu Ansicht Modell Klasse

export class MainMenuVM { 
    public visible: boolean; 
    constructor(
    ) { this.visible = true; } 
} 

Ich versuche, ein Menü zu erstellen, die Symbole und Text, kann aber gehen schmal, um nur Icons zu zeigen. Ich werde dieses Ereignis nach oben zu einer übergeordneten Komponente ausgeben, um die Position des Containers neben dem Menü zu ändern. Das Auslösen eines Inhaltscontainers zur Maximierung führt dazu, dass das Menü eng wird - ich sage nicht, dass dies der beste Weg ist, aber ich möchte diese spezielle Frage lösen, bevor ich tiefer gehe.

Bitte beachten Sie: Ich bin hier nicht auf eine Eingabesteuerung - nur Datenbindung an eine Komponente, so dass ich dann die Benutzeroberfläche ändern kann. Diese

ist von dem Winkel Spickzettel

<my-cmp [(title)]="name"> 
Sets up two-way data binding. Equivalent to: <my-cmp [title]="name" (titleChange)="name=$event"> 

Vielen Dank im Voraus!

UPDATE

Integration des Code von der akzeptierten Antwort und die Anpassung für meinen speziellen Anwendungsfall hier den endgültige Arbeitscode:

app.html

...header html content 

// This is what I started with 
<!--<menu [menuvisible]="true" (menuvisibleChange)="menuvisible=$event"></menu>--> 

// This is two way data binding 
// 1. Banana-in-a-box is the input parameter 
// 2. Banana-in-a-box is also the output parameter name (Angular appends it's usage with Change in code - to follow shortly) 
// 3. Banana-in-a-box is the short hand way to declare the commented out code 
// 4. First parameter (BIAB) refers to the child component, the second refers the variable it will store the result into. 
// 5. If you just need an input use the remmed out code with just the first attribute/value 
<menu [(menuvisible)]="menuvisible"></menu> 

.. div content start 
<router-outlet></router-outlet> 
.. div content end 

app.component.ts (root)

export class AppComponent implements OnInit{ 
    menuvisible: Boolean; 
} 

menu.component.ts (Kind root)

export class MenuComponent implements OnInit { 
    // Parameters - notice the appending of "Change" 
    @Input() menuvisible: boolean; 
    @Output() menuvisibleChange: EventEmitter<boolean> = new EventEmitter<boolean>(); 

    // Init 
    ngOnInit() { 
     // Populate menu - fetch application list  
     this.getApplications(); 

     // Initially we want to show/hide the menu depending on the input parameter 
     (this.menuvisible === true) ? this.showMenu() : this.hideMenu(); 
    } 

    //...more code 
} 

menu.html

<div id="menu" [ngClass]="menuStateClass" style="position: absolute; top:0px; left: 0px;z-index: 800; height: 100%; color: #fff; background-color: #282d32"> 
    <div style="margin-top: 35px; padding: 5px 0px 5px 0px;"> 

     <ul class="menuList" style="overflow-x: hidden;"> 
      <li>IsMenuVisible:{{menuvisible}}</li> 
      <li style="border-bottom: 1px solid #3d4247"><a (click)="toggleMenu()"><i class="fa fa-bars menuIcon" style="color: white; font-size: 16px;"></i></a></li> 
      <li *ngFor="#app of applications"> 
       <a [routerLink]="[app.routerLink]"> 
        <i class="menuIcon" [ngClass]="app.icon" [style.color]="app.iconColour" style="color: white;"></i> 
        <span [hidden]="menuStateTextHidden">{{ app.name }}</span> 
       </a> 
      </li> 
     </ul> 

    </div> 
</div> 

Denken Sie daran, zu importieren, was Sie brauchen zum Beispiel

import {Component, EventEmitter, OnInit, Input, Output} from 'angular2/core';

Sehr zu empfehlen Dieses Video auf You Tube: Angular 2 Tutorial (2016) - Inputs and Outputs

+0

Ich finde deine Frage ziemlich verwirrend. Die Fehlermeldungen IMHO passen nicht zum angegebenen Code. Mir ist nicht klar, was du eigentlich machen willst. '' macht nicht viel Sinn. Warum solltest du eine Zwei-Wege-Bindung an "wahr" haben wollen? Dies macht auch keinen Sinn. "[(Menumodel.visible)] =" menumodel.visible "'. Sie können keine Eigenschaft mit einem '.' versehen und auf diese Weise eine Bindung an eine Untereigenschaft herstellen. –

+0

Ich habe die Frage mit einem Snippet vom Angular Cheat Sheet aktualisiert. Es zeigt eine Komponente mit Zwei-Wege-Datenbindung. Ich vermute also, dass ich tun müsste, was ich in dem Spickzettel zusammen mit deiner Antwort unten finde. z.B. ? – DanAbdn

+0

menuvisible und vis sind einzelne Eigenschaften. menumodel war eine klassenbasierte Variable, wie auch das Hauptmenü. Der Code wurde weiterentwickelt, da ich diese Frage entschuldigen möchte. – DanAbdn

Antwort

27

Zwei-Wege-Bindung Sie brauchen etwas, wie:

@Component({ 
    selector: 'menu', 
    template: ` 
<button (click)="menuvisible = !menuvisible; menuvisibleChange.emit(menuvisible)">toggle</button> 
<!-- or 
    <button (click)="toggleVisible()">toggle</button> --> 
`, 
    // HTTP_PROVIDERS should now be imports: [HttpModule] in @NgModule() 
    providers: [/*HTTP_PROVIDERS*/, ApplicationService], 
    // This should now be added to declarations and imports in @NgModule() 
    // imports: [RouterModule, CommonModule, FormsModule] 
    directives: [/*ROUTER_DIRECTIVES, FORM_DIRECTIVES, NgClass, NgForm*/] 
}) 
export class MenuComponent implements OnInit { 
    @Input() menuvisible:boolean; 
    @Output() menuvisibleChange:EventEmitter<boolean> = new EventEmitter<boolean>(); 

    // toggleVisible() { 
    // this.menuvisible = !this.menuvisible;  
    // this.menuvisibleChange.emit(this.menuvisible); 
    // } 
} 

Und verwenden Sie es wie

@Component({ 
    selector: 'some-component', 
    template: ` 
<menu [(menuvisible)]="menuVisibleInParent"></menu> 
<div>visible: {{menuVisibleInParent}}</div> 
` 
    directives: [MenuComponent] 
}) 
class SomeComponent { 
    menuVisibleInParent: boolean; 
} 
+0

Vielen Dank - aktualisierte Antwort mit dem Code - Ich verstehe viel besser jetzt. – DanAbdn

+0

Funktioniert das noch? Probleme beim Reproduzieren in 2.0.0-rc4. – sdornan

+0

Sollte fast unverändert funktionieren. 'NgForm' und' NgClass' müssen nicht mehr in 'directives' aufgelistet werden. –

4

I habe einen kurzen Plunkr erstellt.

ngModel Like Two-Way-Databinding for components

Sie haben mindestens zwei Möglichkeiten, um eine Zwei-Wege-Datenbindung für Komponenten

V1 zu erstellen: Mit ngModel wie Syntax, da haben Sie eine @Output Eigenschaft mit dem gleichen Namen Zeile erstellen die @Input Eigenschaft + „Change“ am Ende des @Output Eigenschaftsnamen

@Input() name : string; 
@Output() nameChange = new EventEmitter<string>(); 

mit V1 Sie nun auf die Child-Komponente mit der ngModel Syntax binden können

[(name)]="firstname" 

V2. Erstellen Sie einfach ein @Input und @Output Eigenschaft mit dem Sie

bevorzugen Benennung
@Input() age : string; 
@Output() ageChanged = new EventEmitter<string>(); 

mit V2 Sie zwei Attribute erstellen haben die Zwei-Wege-Datenbindung

[age]="alter" (ageChanged)="alter = $event" 

geordnete Komponente

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

@Component({ 
    selector: 'my-app', 
    template: `<p>V1 Parentvalue Name: "{{firstname}}"<br/><input [(ngModel)]="firstname" > <br/><br/> 
       V2 Parentvalue Age: "{{alter}}" <br/><input [(ngModel)]="alter"> <br/><br/> 

       <my-child [(name)]="firstname" [age]="alter" (ageChanged)="alter = $event"></my-child></p>` 
}) 
export class AppComponent { 
    firstname = 'Angular'; 
    alter = "18"; 
} 
zu erhalten

Kind Komponente

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

@Component({ 
    selector: 'my-child', 
    template: `<p>V1 Childvalue Name: "{{name}}"<br/><input [(ngModel)]="name" (keyup)="onNameChanged()"> <br/><br/> 
       <p>V2 Childvalue Age: "{{age}}"<br/><input [(ngModel)]="age" (keyup)="onAgeChanged()"> <br/></p>` 
}) 
export class ChildComponent { 
    @Input() name : string; 
    @Output() nameChange = new EventEmitter<string>(); 

    @Input() age : string; 
    @Output() ageChanged = new EventEmitter<string>(); 

    public onNameChanged() { 
     this.nameChange.emit(this.name); 
    } 

    public onAgeChanged() { 
     this.ageChanged.emit(this.age); 
    } 
}