Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 two way data binding with ngModel

Tags:

angular

First off I am new to Typescript and Angular 2 and this seems like an obvious answer but I can't seem to get it to work. I have the following model

export interface IBrand {
    brandID: number;
    name: string;
    image: string;
}

Then I have the component class

import { Component, OnInit }  from '@angular/core';
import { Router, RouteParams } from '@angular/router-deprecated'
import { bootstrap } from '@angular/platform-browser-dynamic';

import { IBrand } from './brand';
import { BrandService } from './brand.service';

@Component({
    selector: 'data-bind',
    templateUrl: 'app/dashboardApp/brands/brand-list.component.html',
    styleUrls: ['app/dashboardApp/brands/brand-list.component.css']
})

export class BrandListComponent implements OnInit {
    brands: IBrand[];
    errorMessage: string;
    newBrand: IBrand;
    pageTitle: string = 'Brands';

    constructor(private _brandService: BrandService,
        private _router: Router) {
    }

    ngOnInit(): void {
        this._brandService.getBrands()
            .subscribe(
            brands => this.brands = brands,
            error => this.errorMessage = <any>error);
    }    
}

And then I have the following html

<div class="form-group">
    <label for="brandName">Brand:</label>
    <input type="text" class="form-control" placeholder="Name" id="brandName" [(ngModel)]="newBrand.name" />
</div>

I can't get the properties of IBrand to work successfully and I get the error

platform-browser.umd.js:962 ORIGINAL EXCEPTION: TypeError: Cannot read property 'name' of undefined

However I can bind it easily to something like pageTitle. Any ideas that can point me in the right direction?

like image 877
Derked Avatar asked Jun 11 '16 15:06

Derked


3 Answers

It's been a while since I have asked this question, and it's starting to get some views so I will add my answer.

First I would need to change my interface to a class and add a constructor.

export class Brand {
  constructor() {}
  brandID: number;
  name: string;
  image: string;
}

Now that I have a constructor I can use the new operator to instantiate the object.

export class BrandListComponent implements OnInit {
  brands: Brand[];
  errorMessage: string;
  newBrand: Brand = new Brand();
  pageTitle: string = 'Brands';

  (...)
}

Now I have the desired brand initialized without any data and I can bind it to the model. Hope this helps.

like image 143
Derked Avatar answered Oct 21 '22 06:10

Derked


You could follow this approach if you don't want to use class.

export interface IBrand {
brandID: number;
name: string;
image: string;
}

And now you could create empty objects for typed variables like this.

brand: IBrand = {} as IBrand;

Avoid using classes if you just want to use it for type safety instead use interface as best practice to make your bundle size smaller.

like image 22
Gunjan Khanwilkar Avatar answered Oct 21 '22 06:10

Gunjan Khanwilkar


I think that you need to initialize your newBrand property as described below:

export class BrandListComponent implements OnInit {
  brands: IBrand[];
  errorMessage: string;
  newBrand: IBrand = {}; // <-----
  pageTitle: string = 'Brands';

  (...)
}

In your case, this property is never initialized and you have the error:

Cannot read property 'name' of undefined

like image 36
Thierry Templier Avatar answered Oct 21 '22 04:10

Thierry Templier