Kuni Kuni - 1 month ago 11
AngularJS Question

Detect changes to ng-model in child component and pass the data in AngularJS

I'm creating a big component based angular 1.5.8 application. There are about 18 different components within a parent component. For this purpose, each components template has inputs which is a part of parent component form. So far everything works fine. What I'm stuck at, and really in need of logic, is how to detect the changes made to the inputs in each component so the data can be saved in shared service for the parent component to fetch before sending the form data to the server.

From the parent component

<form name="claimForm" novalidate>
<!-- Section Title -->
<section name="Add new claim" class="section-background section animated fadeIn" ng-cloak>

<!-- Pharmacy Info -->
<pharmacy-info claim-form="claimForm"></pharmacy-info>

</section>
</form>


PharmacyInfo has just a simple inputs

<md-input-container flex-gt-sm="70">
<label>Pharmacy Name</label>
<input type="text"
flex
tabindex="4"
id="pharmacyName"
name="pharmacyName"
md-maxlength="80"
aria-label="Pharmacy Name"
ng-model="$ctrl.pharmacy.name" />
<div ng-messages="$ctrl.claimForm.pharmacyName.$error">
<div ng-message="md-maxlength">
Pharmacy name is too long!
</div>
</div>
</md-input-container>


Pharmacy Component

(function () {
'use strict';

angular.module('sempp')
.component('pharmacyInfo', {
templateUrl: 'Scripts/src/views/pharmacy/pharmacy.info.template.html',
controller: PharmacyInfoComponentController,
bindings: {
claimForm: '<'
}
});

PharmacyInfoComponentController.$inject = ['PharmacyService']

function PharmacyInfoComponentController(PharmacyService) {
var $ctrl = this;


$ctrl.$doCheck = function () {

//console.log($ctrl.pharmacy);
PharmacyService.setPharmacy($ctrl.pharmacy);
}


}// end controller function

})();


The problem I'm having is that I can't have an "update" button on each component for users to click everytime they enter the value in the form. It won't be too user friendly.

The other issue I'm running into is using $onChanges. It's not detecting any changes made to the form in the Child Component. Not sure how to make that happen. I'm still reading the docs though.

However, if I use $doCheck, it does detect the changes, but it's running everytime I make a change on any more the form. Now, with about 18 components and many input forms in each components, I think that'll just slow down the application.

What're my choices? How can I make it seamless such that when the user enters the value, that value is either saved in shared services, or saved in parent component object (whichever is better). I will then need to send the data to the database to be inserted.

Answer

Use the ng-change directive on inputs:

<md-input-container flex-gt-sm="70">
    <label>Pharmacy Name</label>
    <!-- USE ng-change directive -->
    <input type="text"
            ng-change="$ctrl.updatePharmacyService()"               
            flex
            tabindex="4"
            id="pharmacyName"
            name="pharmacyName"
            md-maxlength="80"
            aria-label="Pharmacy Name"
            ng-model="$ctrl.pharmacy.name" />
    <div ng-messages="$ctrl.claimForm.pharmacyName.$error">
        <div ng-message="md-maxlength">
            Pharmacy name is too long!
        </div>
    </div>
</md-input-container>

The ng-change directive evaluates its AngularJS Expression only the when the user enters an input. This will have less overhead than using the $doCheck function which evaluates every digest cycle.

For more information, see SO: AngularJs 1.5 - Component does not support Watchers, what is the work around?

Comments