Linked Questions

Popular Questions

Angular 6 attribute directive field undefined

Asked by At

I work with Angular 6. I have a form with 4 fields. Two of them are the price and the quantity. I want to display in another field the multiplication of price and quantity.

I defined an attribute directive. I want to display in a div the field of directive paModel totalPrice. I defined an event in the form fields.

This is my form

<form novalidate [formGroup]="form" (ngSubmit)="submitForm(form)">
  <div class="form-group" *ngFor="let control of form.productControls">
    <label>{{ control.label }}</label>
    <input
      class="form-control"
      [(ngModel)]="newProduct[control.modelProperty]"
      name="{{ control.modelProperty }}"
      formControlName="{{ control.modelProperty }}"
      [paModel]="newProduct[control.modelProperty]"
      (paModelChange)="newProduct[control.modelProperty] = $event"
      [pa-product]="newProduct"
      #paModel="paModel"
    />
    <ul class="text-danger list-unstyled" *ngIf="(formSubmitted || control.dirty) && !control.valid">
      <li *ngFor="let error of control.getValidationMessages()">{{ error }}</li>
    </ul>
  </div>
  <div class="bg-primary text-white">{{ paModel.totalPrice }}</div>
  <button
    class="btn btn-primary"
    type="submit"
    [disabled]="formSubmitted && !form.valid"
    [class.btn-secondary]="formSubmitted && !form.valid"
  >
    Create
  </button>
</form>

The attribute directive name is paModel. This is my paModel directive

import { Input, Output, EventEmitter, Directive, HostBinding, HostListener, SimpleChange } from "@angular/core";
import {Product } from "./product.model"

@Directive({
    selector: "input[paModel]",
    exportAs: "paModel"
})
export class PaModel {

    direction: string = "None";

    @Output("pa-totalprice")
    totalPrice: number = 0;

    @Input("paModel")
    modelProperty: string;

    @Input("pa-product")
    product: Product;

    @HostBinding("value")
    fieldValue: string = "";

    ngOnChanges(changes: { [property: string]: SimpleChange }) {
        console.log("en ngOnChanges");
        let change = changes["modelProperty"];
        if (change.currentValue != this.fieldValue) {
            this.fieldValue = changes["modelProperty"].currentValue || "";
            this.direction = "Model";
            this.totalPrice = 0;
        }
    }

    @Output("paModelChange")
    update = new EventEmitter<string>();

    @HostListener("input", ["$event.target.value"])
    updateValue(newValue: string) {
        console.log("en updateValue");
        console.log("name ",this.product.name)
        console.log("price ",this.product.price)
        console.log("quantity ",this.product.quantity)
        if (this.product.price != undefined && this.product.quantity != undefined) {
            this.totalPrice = this.product.price * this.product.quantity;
        } else {
            this.totalPrice = 0;
        }
        this.fieldValue = newValue;
        this.update.emit(newValue);
        this.direction = "Element";
    }
}

In the console I see the error

ERROR TypeError: Cannot read property 'totalPrice' of undefined
    at Object.eval [as updateRenderer] (ProductFormComponent.html:18)
    at Object.debugUpdateRenderer [as updateRenderer] (core.js:10879)
    at checkAndUpdateView (core.js:10255)
    at callViewAction (core.js:10491)
    at execComponentViewsAction (core.js:10433)
    at checkAndUpdateView (core.js:10256)
    at callViewAction (core.js:10491)
    at execComponentViewsAction (core.js:10433)
    at checkAndUpdateView (core.js:10256)
    at callWithDebugContext (core.js:11143)

How can I display the field totalPrice in a div?

EDITED

I modified my code. Now I have the html

<div class="form-group bg-info text-white p-2">
  <input class="bg-primary text-white" [(paModel)]="newProduct" #paModel="paModel" />
  <div *ngIf="paModel" class="bg-primary text-white">Total Price : {{ paModel.totalPriceString }}</div>
</div>

And I have two methods

ngOnChanges(changes: { [property: string]: SimpleChange }) {

    let change = changes["modelProperty"];
    /* if (change.currentValue != this.fieldValue) { */

        this.fieldValue = changes["modelProperty"].currentValue || "";

        this.direction = "Model";
        if (this.product.price != undefined && this.product.quantity != undefined) {
        this.totalPrice = this.product.price * this.product.quantity;
    } else {

        this.totalPrice = 0;
    }

    this.totalPriceString = this.totalPrice.toString();

   /*  } */
}

@Output("paModelChange")
update = new EventEmitter<string>();

@HostListener("input", ["$event.target.value"])
updateValue(newValue: string) {

    if (this.product.price != undefined && this.product.quantity != undefined) {
        this.totalPrice = this.product.price * this.product.quantity;
    } else {
        this.totalPrice = 0;
    }
    this.fieldValue = newValue;


    this.update.emit(newValue);
    this.direction = "Element";
    this.totalPriceString = this.totalPrice.toString();
} 

At the end of these methods totalPrice has the multiplication, but the values is no displayed in the div.

How can I fix this?

Related Questions