18

En Angulaire2 (Bêta 6) j'ai un composant pour un menu principal.Angular2 - liaison de données bidirectionnelle sur une propriété de variable de composant/classe de composant?

<mainmenu></mainmenu> 

Je veux lier un booléen pour large ou étroit. Alors je l'ai fait dans ce:

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

Mais ce que je veux (je pense) est de se lier à une propriété de classe javascript (comme je peux avoir d'autres choses à lier, mais veulent être rangé en utilisant une seule classe le composant).

Je reçois une erreur

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

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

Si je tente la même chose avec une seule variable au lieu d'une classe que je reçois:

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

Cependant, cette (? Une façon contraignante) ne semble travaillez (mais je pourrais vouloir déclencher le menu pour qu'il devienne large/étroit d'un autre composant, donc je pense que cela devrait être une propriété de liaison de données bidirectionnelle):

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

C'est un peu de mon élément de 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 

} 

Voici mon MainMenu Voir Modèle de

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

Je suis en train de créer un menu qui a des icônes et du texte, mais peut aller étroit pour juste montrer des icônes. Je vais émettre cet événement vers le haut à un composant parent pour modifier la position du conteneur à côté du menu. Déclencher un conteneur de contenu à maximisé va déclencher le menu pour aller plus loin - je ne dis pas que c'est la meilleure façon, mais je voudrais résoudre cette question particulière avant d'aller plus loin.

Veuillez noter: Je ne suis pas en liaison de données avec un contrôle d'entrée ici - juste la liaison de données à un composant afin que je puisse ensuite modifier l'interface utilisateur.

C'est de la antisèche angulaire

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

Merci à l'avance!

MISE À JOUR

L'intégration du code de la réponse acceptée et l'adaptation pour mon cas particulier d'utilisation ici le code de travail final:

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 (enfant de la racine)

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> 

Rappelez-vous d'importer ce que vous devez par exemple

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

Je recommande vivement cette vidéo sur You Tube: Angular 2 Tutorial (2016) - Inputs and Outputs

+0

Je trouve votre question assez confuse. Les messages d'erreur IMHO ne correspondent pas avec le code fourni. Ce n'est pas clair pour moi ce que tu veux vraiment faire. '' n'a pas beaucoup de sens. Pourquoi voudriez-vous que la liaison bidirectionnelle soit 'true'? Cela n'a pas non plus de sens '[(menumodel.visible)] =" menumodel.visible "'. Vous ne pouvez pas avoir une propriété avec un '.' et vous pouvez lier à une sous-propriété de cette façon. –

+0

J'ai mis à jour la question avec un extrait de la feuille de triche angulaire. Il montre un composant avec une liaison de données bidirectionnelle. Donc, je devine que je devrais faire ce que je trouve dans la feuille de triche couplée à votre réponse ci-dessous. par exemple. ? – DanAbdn

+0

menuvisible et vis sont des propriétés uniques. menumodel était une variable basée sur la classe, tout comme le menu principal. Le code a évolué comme j'ai écrit cette question des excuses. – DanAbdn

Répondre

27

Pour deux voies de liaison dont vous avez besoin quelque chose comme:

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

et de l'utiliser comme

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

Merci beaucoup - mise à jour réponse avec le code - je comprends beaucoup mieux maintenant. – DanAbdn

+0

Est-ce que cela fonctionne encore? J'ai du mal à reproduire cela dans 2.0.0-rc4. – sdornan

+0

Devrait fonctionner presque inchangé. 'NgForm' et' NgClass' n'ont plus besoin d'être listés dans 'directives'. –

4

I J'ai créé un petit plunkr.

ngModel Like Two-Way-Databinding for components

Vous avez au moins deux possibilités pour la création d'une liaison de données à deux voies pour les composants

V1: Avec ngModel Comme syntaxe, il vous faut créer une propriété @output avec la même ligne de nom de la @input propriété + « Change » à la fin du nom de la propriété @output

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

avec V1, vous pouvez maintenant lier à la composante enfant avec le ngModel Syntaxe

[(name)]="firstname" 

V2. Il suffit de créer une propriété @input et @output avec le nommant vous préférez

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

avec V2, vous devez créer deux attributs pour obtenir les deux sens databinding

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

Parent Component

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

Composant enfant

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