DanAbdn DanAbdn - 1 month ago 6x
AngularJS Question

Angular2 - two way databinding on a component variable / component class property?

In Angular2 (Beta 6) I have a component for a main menu.


I want to bind a boolean for wide or narrow. So I made it into this:

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

But what I want (I think) is to bind to a javascript class property (as I may have other things to bind but want to be tidy by using a single class in the component).

I get an error

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


If I try the same with a single variable instead of a class I get:

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

However this (one way binding?) does seem to work (but I might want to trigger the menu to go wide/narrow from another component so felt this should be a two-way data bound property):

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

This is a bit of my menu component:

selector: 'menu',
templateUrl: './app/menu.html',
providers: [HTTP_PROVIDERS, ApplicationService],
export class MenuComponent implements OnInit {

mainmenu: MainMenuVM;

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

// ...ngOnInit, various functions


Here is my MainMenu View Model class

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

I'm trying to create a menu which has icons and text, but can go narrow to just show icons. I will emit this event upwards to a parent component to alter the position of the container next to the menu. Triggering a content container to maximised will trigger the menu to go narrow - I am not saying this is the best way, but I would like to resolve this particular question before going deeper.

Please note: I am not databinding to an input control here - just databinding to a component so I can then modify the UI.

This is from the Angular cheatsheet

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

Thanks in advance!


Integrating the code from the accepted answer and adapting for my particular use case here the final working code:


...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
.. 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

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

//...more code


<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 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>


Remember to import what you need e.g.

import {Component, EventEmitter, OnInit, Input, Output} from

Highly recommend this video on You Tube:
Angular 2 Tutorial (2016) - Inputs and Outputs


For two-way binding you need something like:

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

And use it like

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