首页 文章

Angular2 - 组件变量/组件类属性的双向数据绑定?

提问于
浏览
21

在Angular2(Beta 6)中,我有一个主菜单组件 .

<mainmenu></mainmenu>

我想为宽或窄绑定一个布尔值 . 所以我做到了这个:

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

但我想要的(我认为)是绑定到一个javascript类属性(因为我可能有其他东西需要绑定,但希望通过在组件中使用单个类来整洁) .

我收到一个错误

EXCEPTION:模板解析错误:无效的属性名称'menumodel.visible'(“] [(menumodel.visible)] =”menumodel.visible“>

如果我尝试使用单个变量而不是类,我会得到:

模板解析错误:解析器错误:意外的令牌'='

然而,这(单向绑定?)似乎确实有效(但我可能想触发菜单从另一个组件扩展/缩小,所以觉得这应该是一个双向数据绑定属性):

<menu [vis]="true"></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

}

这是我的MainMenu View Model类

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

我正在尝试创建一个包含图标和文本的菜单,但可以缩小到只显示图标 . 我将向上发送此事件到父组件以更改菜单旁边的容器位置 . 触发内容容器以最大化将触发菜单缩小 - 我不是说这是最好的方法,但我想在深入之前解决这个特定的问题 .

请注意:我不是在这里数据绑定到输入控件 - 只是数据绑定到组件,然后我可以修改UI .

这是来自Angular cheatsheet

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

提前致谢!

UPDATE

整合接受的答案中的代码并根据我的特定用例调整最终的工作代码:

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 (child of 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>

请记住导入您需要的内容,例如

从'angular2 / core'导入{Component,EventEmitter,OnInit,Input,Output};

强烈推荐You Tube上的这个视频:Angular 2 Tutorial (2016) - Inputs and Outputs

2 回答

  • 6

    对于双向绑定,您需要以下内容:

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

    并使用它

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

    我创造了一个短的傻瓜 .

    ngModel Like Two-Way-Databinding for components

    您至少有两种可能性为组件创建双向数据绑定

    V1:使用ngModel Like语法,您必须在@Output属性名称的末尾创建一个@Output属性,该属性具有相同的名称行@Input属性“Change”

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

    使用V1,您现在可以使用ngModel语法绑定到子组件

    [(name)]="firstname"
    

    V2 . 只需使用您喜欢的命名创建一个@Input和@Output属性

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

    使用V2,您必须创建两个属性才能获得双向数据绑定

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

    父组件

    import { Component } from '@angular/core';
    
    @Component({
       selector: 'my-app',
       template: `<p>V1 Parentvalue Name: "{{firstname}}"
    <input [(ngModel)]="firstname" >

    V2 Parentvalue Age: "{{alter}}"
    <input [(ngModel)]="alter">

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

    子组件

    import { Component, Input, Output, EventEmitter } from '@angular/core';
    
    @Component({
       selector: 'my-child',
       template: `<p>V1 Childvalue Name: "{{name}}"
    <input [(ngModel)]="name" (keyup)="onNameChanged()">

    <p>V2 Childvalue Age: "{{age}}"
    <input [(ngModel)]="age" (keyup)="onAgeChanged()">
    </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); } }

相关问题