Vortilion
Vortilion

Reputation: 424

How to realize template component with input field in AngularJS

We are using AngularJS 1.6 and bootstrap 4.3.1 in our project to build the UI. Now I want to build a simple component which basically makes using bootstrap's form-group elements easier.

I tried writing the component like that:

Template:

<div class="form-group">
<label
    for="input-{{::$ctrl.name}}"
    class="input-label mb-1"
    ng-class="{'disabled': $ctrl.isDisabled, 'required': $ctrl.isRequired}"
    ng-bind="::$ctrl.label">
</label>
<input
    tabindex="{{$ctrl.tabindex}}"
    ng-readonly="$ctrl.isReadonly"
    ng-model="$ctrl.model"
    type="{{::$ctrl.type}}"
    id="input-{{::$ctrl.name}}"
    class="form-control"
    ng-class="{'negative': $ctrl.hasNegativeStyle}"
    ng-required="$ctrl.isRequired">

JavaScript:

(function () {
'use strict';

var component = {
    templateUrl: 'app/components/bootstrap/form-group-input/form-group-input.component.html',
    bindings: {
        name: '@',
        label: '@',
        model: '<',
        isReadonly: '<',
        isRequired: '<',
        isDisabled: '<',
        hasNegativeStyle: '<',
        type: '@',
        tabindex: '@'
    }
};

angular
    .module('collphir.common')
    .component('cwpFormGroupInput', component);
})();

Problem now is the model-binding. Changing the input in the component won't affect the parent's model, because it's one-way-binding. But how can I achieve that without gong back to the old two-way-binding (which we don't want cause we want to mgirate to Angular anytime soon)?

Upvotes: 0

Views: 66

Answers (2)

Vortilion
Vortilion

Reputation: 424

I found a way to achieve what I want:

JavaScript:

(function () {
'use strict';

var component = {
    templateUrl: 'app/components/bootstrap/form-group-input/form-group-input.component.html',
    bindings: {
        name: '@',
        label: '@',
        model: '<',
        isReadonly: '<',
        isRequired: '<',
        isDisabled: '<',
        hasNegativeStyle: '<',
        type: '@',
        tabindex: '@',
        modelChange: '&'
    }
};

angular
    .module('collphir.common')
    .component('cwpFormGroupInput', component);
})();

HTML-Template:

<div class="form-group">
<label
    for="input-{{::$ctrl.name}}"
    class="input-label mb-1"
    ng-class="{'disabled': $ctrl.isDisabled, 'required': $ctrl.isRequired}"
    ng-bind="::$ctrl.label">
</label>
<input
    tabindex="{{$ctrl.tabindex}}"
    ng-readonly="$ctrl.isReadonly"
    ng-model="$ctrl.model"
    type="{{::$ctrl.type}}"
    id="input-{{::$ctrl.name}}"
    class="form-control"
    ng-class="{'negative': $ctrl.hasNegativeStyle}"
    ng-change="$ctrl.modelChange({$event: $ctrl.model})"
    ng-required="$ctrl.isRequired">
</div>

Example use of this component:

<cwp-form-group-input
    class="mb-2"
    name="brutto"
    label="{{$ctrl.text.labelBrutto}}"
    model="$ctrl.sVEinkommen"
    is-readonly="$ctrl.isReadonly"
    type="number"
    model-change="$ctrl.sVEinkommen=$event"
    tabindex="1">
</cwp-form-group-input>

Upvotes: 0

jtate
jtate

Reputation: 2696

If you want a model change in a child component to also be reflected in its parent component, you have to use two-way binding. So in your component, you can set your binding like this:

bindings: {
    // ...
    model: '=',
    // ...
}

The = denotes two-way binding, while the < denotes one-way binding. See this quote directly from the AngularJS documentation:

If you pass an object to a component like this - bindings: {item: '='}, and modify one of its properties, the change will be reflected in the parent component.

Upvotes: 0

Related Questions