2016-02-25 17 views
18

In Angular2 (Beta 6) ho un componente per un menu principale.Angular2 - associazione bidirezionale su una proprietà componente variabile/classe componente?

<mainmenu></mainmenu> 

Voglio legare un booleano per largo o stretto. Così ho fatto in questo modo:

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

Ma quello che voglio (credo) è quella di legarsi a una proprietà di classe javascript (come io possa avere altre cose da legare, ma voler essere ordinata utilizzando una singola classe in il componente).

ottengo un errore

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

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

Se provo la stessa cosa con una sola variabile, invece di una classe ottengo:

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

Tuttavia questa (? Un modo vincolante) non sembrano lavoro (ma potrei voler attivare il menu per andare largo/stretto da un altro componente, quindi questa dovrebbe essere una proprietà bidirezionale dei dati):

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

Questo è un po 'della mia componente Menu:

@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 

} 

Qui è la mia classe MainMenu View Modello

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

Sto cercando di creare un menu che ha le icone e il testo, ma posso andare ristretto per mostrare solo le icone. Emetteremo questo evento verso l'alto a un componente genitore per modificare la posizione del contenitore accanto al menu. Attivare un contenitore di contenuti per massimizzare farà sì che il menu si restringa - Non sto dicendo che questo è il modo migliore, ma vorrei risolvere questa particolare domanda prima di andare più a fondo.

Nota: non sto collegando i dati a un controllo di input qui - solo collegando i dati a un componente in modo da poter quindi modificare l'interfaccia utente.

Questo è dal bigino angolare

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

Grazie in anticipo!

UPDATE

integrazione del codice della risposta accettata e l'adattamento per il mio particolare caso d'uso qui il codice finale di lavoro:

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 (figlio della radice)

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> 

Ricordati di importare quello che ti serve per esempio

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

Raccomandiamo gli video su You Tube: Angular 2 Tutorial (2016) - Inputs and Outputs

+0

La trovo abbastanza confusa. I messaggi di errore IMHO non si adattano al codice fornito. Non mi è chiaro cosa vuoi veramente fare. '' non ha molto senso. Perché vuoi che il binding a due vie sia 'true'? Anche questo non ha senso '[(menumodel.visible)] =" menumodel.visible "'. Non è possibile avere una proprietà con un '.' e si può associare a una sottoproprietà in questo modo. –

+0

Ho aggiornato la domanda con uno snippet da Angular Cheat Sheet. Mostra un componente con associazione dati bidirezionale. Quindi immagino che avrei bisogno di fare quello che trovo nel cheat sheet insieme alla tua risposta qui sotto. per esempio. ? – DanAbdn

+0

menuvisible e vis sono proprietà singole. il menumodel era una variabile basata sulla classe, come lo era il mainmenu. Il codice si è evoluto mentre ho scritto questa domanda scuse. – DanAbdn

risposta

27

Per due vie vincolante hai bisogno di qualcosa di simile:

@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); 
    // } 
} 

e usarlo come

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

Grazie mille - risposta aggiornata con il codice - Capisco molto meglio ora. – DanAbdn

+0

Funziona ancora? Problemi nella riproduzione di questo in 2.0.0-rc4. – sdornan

+0

Dovrebbe funzionare quasi invariato. 'NgForm' e' NgClass' non devono più essere elencati in 'direttive '. –

4

I Ho creato un breve plunkr.

ngModel Like Two-Way-Databinding for components

Avete almeno due possibilità per per creare un associazione dati a due vie per i componenti

V1: Con ngModel come sintassi, non è necessario creare una proprietà @Output con la stessa linea del nome @Input proprietà + "Change" alla fine del nome della proprietà @Output

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

con V1 ora è possibile associare al componente figlio con la sintassi ngModel

[(name)]="firstname" 

V2. Basta creare una proprietà @Input e @Output con la denominazione si preferisce

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

con V2 è necessario creare due attributi per ottenere il doppio senso associazione dati

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

componente principale

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"; 
} 

Componente figlio

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); 
    } 
} 
Problemi correlati