DenisMP
DenisMP

Reputation: 993

Angular2 can't bind error using "Build a Better Angular 2 Application with Redux"?

I am trying to imitate Lukas Ruebbelke's example at:

His example

I am getting the error below, and I don't know how to fix it. Can someone provide a clue to me?

Lukas' version is an older angular2, but the latest one does not recognized "directives", so I moved that to the app.modules.ts file which may be where the problem is starting.

FYI, I created the project from scratch as per the instructions on the angular.io web site.

Error Message from the browser:

    compiler.js:466 Uncaught Error: Template parse errors:
Can't bind to 'observation' since it isn't a known property of 'observation-detail'.
1. If 'observation-detail' is an Angular component and it has 'observation' input, then verify that it is part of this module.
2. If 'observation-detail' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.
3. To allow any property add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component. ("ion-detail
        (saved)="saveObservation($event)" (cancelled)="resetObservation($event)"
        [ERROR ->][observation]="selectedObservation | async">Select an Observation</observation-detail>
    </div>
  <"): ng:///AppModule/Observations.html@10:8

The offending file, I think. I marked it with bold and italics which shows up as "***".

    import {Component} from '@angular/core';
import {Observable} from "rxjs/Observable";
import {Store} from '@ngrx/store';
import {ObservationsService} from '../common/services/observations.service';
import {AppStore} from '../common/models/appstore.model';
import {Observation} from '../common/models/observation.model';
import {ObservationsList} from './observations-list.component';
import {ObservationDetail} from './observation-detail.component';

// import {Gadget} from '../common/models/gadget.model';
// import {GadgetService} from '../common/services/gadget.service'

@Component({
  selector: 'observations',
  template: `
  <div class="mdl-grid observations">
    <div class="mdl-cell mdl-cell--6-col">
      <observations-list [observations]="observations | async"
        (selected)="selectObservation($event)" (deleted)="deleteObservation($event)">
      </observations-list>
    </div>
    <div class="mdl-cell mdl-cell--6-col">
      <observation-detail
        (saved)="saveObservation($event)" (cancelled)="resetObservation($event)"
        ***[observation]="selectedObservation | async">Select an Observation</observation-detail>***
    </div>
  </div>
  `,
  styles: [`
    .observations {
      padding: 20px;
    }
  `],
  providers: [ObservationsService]
  // directives: [ObservationsList, ObservationDetail]
})
export class Observations {
  observations: Observable<Array<Observation>>;
  selectedObservation: Observable<Observation>;
  // gadget: Observable<Gadget>;

  constructor(private observationsService: ObservationsService,
              // private gadgetService: GadgetService,
              private store: Store<AppStore>) {
    this.observations = observationsService.observations;
    this.selectedObservation = store.select(state => state.selectedObservation);
    this.selectedObservation.subscribe(v => console.log(v));

    // this.gadget = gadgetService.gadget;

    observationsService.loadObservations();
  }

  resetObservation() {
    let emptyItem: Observation = {id: null, fein: 0, name: '', description: ''};
    this.store.dispatch({type: 'SELECT_OBSERVATION', payload: emptyItem});
  }

  selectObservation(item: Observation) {
    this.store.dispatch({type: 'SELECT_OBSERVATION', payload: item});
  }

  saveObservation(item: Observation) {
    this.observationsService.saveObservation(item);

    // Generally, we would want to wait for the result of `itemsService.saveItem`
    // before resetting the current item.
    this.resetObservation();
  }

  deleteItem(item: Observation) {
    this.observationsService.deleteObservation(item);

    // Generally, we would want to wait for the result of `itemsService.deleteItem`
    // before resetting the current item.
    this.resetObservation();
  }
}

Observations component:

    import {Component} from '@angular/core';
import {Observable} from "rxjs/Observable";
import {Store} from '@ngrx/store';
import {ObservationsService} from '../common/services/observations.service';
import {AppStore} from '../common/models/appstore.model';
import {Observation} from '../common/models/observation.model';
import {ObservationsList} from './observations-list.component';
import {ObservationDetail} from './observation-detail.component';

// import {Gadget} from '../common/models/gadget.model';
// import {GadgetService} from '../common/services/gadget.service'

@Component({
  selector: 'observations',
  template: `
  <div class="mdl-grid observations">
    <div class="mdl-cell mdl-cell--6-col">
      <observations-list [observations]="observations | async"
        (selected)="selectObservation($event)" (deleted)="deleteObservation($event)">
      </observations-list>
    </div>
    <div class="mdl-cell mdl-cell--6-col">
      <observation-detail
        (saved)="saveObservation($event)" (cancelled)="resetObservation($event)"
        [observation]="selectedObservation | async">Select an Observation</observation-detail>
    </div>
  </div>
  `,
  styles: [`
    .observations {
      padding: 20px;
    }
  `],
  providers: [ObservationsService]
  // directives: [ObservationsList, ObservationDetail]
})
export class Observations {
  observations: Observable<Array<Observation>>;
  selectedObservation: Observable<Observation>;
  // gadget: Observable<Gadget>;

  constructor(private observationsService: ObservationsService,
              // private gadgetService: GadgetService,
              private store: Store<AppStore>) {
    this.observations = observationsService.observations;
    this.selectedObservation = store.select(state => state.selectedObservation);
    this.selectedObservation.subscribe(v => console.log(v));

    // this.gadget = gadgetService.gadget;

    observationsService.loadObservations();
  }

  resetObservation() {
    let emptyItem: Observation = {id: null, fein: 0, name: '', description: ''};
    this.store.dispatch({type: 'SELECT_OBSERVATION', payload: emptyItem});
  }

  selectObservation(item: Observation) {
    this.store.dispatch({type: 'SELECT_OBSERVATION', payload: item});
  }

  saveObservation(item: Observation) {
    this.observationsService.saveObservation(item);

    // Generally, we would want to wait for the result of `itemsService.saveItem`
    // before resetting the current item.
    this.resetObservation();
  }

  deleteItem(item: Observation) {
    this.observationsService.deleteObservation(item);

    // Generally, we would want to wait for the result of `itemsService.deleteItem`
    // before resetting the current item.
    this.resetObservation();
  }
}

app.module.ts:

    import { BrowserModule }           from '@angular/platform-browser';
import { NgModule }                from '@angular/core';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { AppComponent } from './app.component';

import { Observations } from './observations/observations.component';
import { ObservationsList } from './observations/observations-list.component';
import { ObservationDetail } from './observations/observation-detail.component';


@NgModule({
  declarations: [
    AppComponent,
    Observations,
    ObservationsList, 
    ObservationDetail
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Observation model interface:

    export interface Observation {
    id: number;
    fein: number;
    name: string;
    description: string;
  };

package.json:

    {
  "name": "myapp",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^5.0.2",
    "@angular/common": "^5.0.0",
    "@angular/compiler": "^5.0.0",
    "@angular/core": "^5.0.0",
    "@angular/forms": "^5.0.0",
    "@angular/http": "^5.0.0",
    "@angular/platform-browser": "^5.0.0",
    "@angular/platform-browser-dynamic": "^5.0.0",
    "@angular/router": "^5.0.0",
    "@ngrx/store": "^4.1.1",
    "core-js": "^2.4.1",
    "primeng": "^5.0.0-rc.0",
    "rxjs": "^5.5.2",
    "zone.js": "^0.8.14"
  },
  "devDependencies": {
    "@angular/cli": "1.5.2",
    "@angular/compiler-cli": "^5.0.0",
    "@angular/language-service": "^5.0.0",
    "@types/jasmine": "~2.5.53",
    "@types/jasminewd2": "~2.0.2",
    "@types/node": "~6.0.60",
    "codelyzer": "~3.2.0",
    "jasmine-core": "~2.6.2",
    "jasmine-spec-reporter": "~4.1.0",
    "karma": "~1.7.0",
    "karma-chrome-launcher": "~2.1.1",
    "karma-cli": "~1.0.1",
    "karma-coverage-istanbul-reporter": "^1.2.1",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.1.2",
    "ts-node": "~3.2.0",
    "tslint": "~5.7.0",
    "typescript": "~2.4.2",
    "primeng": "^4.1.0",
    "font-awesome": "^4.7.0"
  }
}

Upvotes: 1

Views: 49

Answers (2)

David Yew
David Yew

Reputation: 417

Based on your package.json, I assumed you had installed @angular/cli.

I would use ng lint --fix to help me fix or point to me the source of the problem.
Hope this will be of help to you.

Secondly, I noticed that you had upgraded @angular/animations to 5.0.2, while other @angular packages at 5.0.0, and would like to encourage you to have the same version for all @angular packages, to avoid unnecessary stress.

Upvotes: 1

DenisMP
DenisMP

Reputation: 993

I found the problem. It was simple but hard to find. I forgot to rename the set item to set observation in the @Input() set item() in the observation-detail.component.ts file.

    export class ObservationDetail {
  originalName: string;
  selectedObservation: Observation;
  @Output() saved = new EventEmitter();
  @Output() cancelled = new EventEmitter();

  @Input() set observation(value: Observation){ <=== Right here!!  This was originally set item()
    if (value) this.originalName = value.name;
    this.selectedObservation = Object.assign({}, value);
  }
}

Upvotes: 1

Related Questions