Tamara
Tamara

Reputation: 2980

Angular: custom directive not updating controller

I started to learn Angular not so long time ago and I'm trying to understand scope, binding and etc.

I have an order details controller:

orderApp.controller('OrderDetailsController', ['$http','$routeParams','$scope','config', function($http, $routeParams, $scope, config){

    var orderCtrl = this;
    orderCtrl.orderId = $routeParams.orderId;
    orderCtrl.order = {};
    orderCtrl.editingView = false;

   ...

}]);

On order details page I want to output all information about selected order. Also we need to give user ability to edit order. Information about editing mode is stored in orderCtrl.editingView.

I decided to create custom directive. If edit mode is off - display text, otherwise display input.

    orderApp.directive('editableText', function(){
    return {
        restrict: 'E',
        scope: {
            property: '=property',
            editMode: '=editMode'
        },
        controller: 'OrderDetailsController',
        controllerAs: 'orderCtrl',
        templateUrl: '/pages/editable-text.html'
    }
});

This is template:

<div class="col-xs-8" ng-if="!editMode">{{property}}</div>
<div class="col-xs-8" ng-if="editMode"><input type="text" class="form-control" ng-model="property"></div>

And this is how I use directive in html files:

 <editable-text property="orderCtrl.order.coid" edit-mode="orderCtrl.editingView"></editable-text>

Text and input are switching when edit mode is on/off. Problem is that orderCtrl.order.coid property is not updated when I change it in input.

Before edit property looks like: enter image description here

Turn on edit mode and change value: enter image description here

Turn off edit mode and we see old value: enter image description here

Do I need to synchronise controller values and directive scope? I thought that with 2-ways binding it should happen automatically. Probably there is any other way to write this functionality? Will appreciate any help.


UPD

Directive code:

    orderApp.directive('editableText', function(){
    return {
        restrict: 'E',
        bindToController: {
            property: '=property',
            editMode: '=editMode'
        },
        controller: 'OrderDetailsController',
        controllerAs: 'orderCtrl',
        templateUrl: '/pages/editable-text.html'
    }
});

Directive template:

<div class="col-xs-8" ng-if="!orderCtrl.editMode">{{orderCtrl.property}}</div>
<div class="col-xs-8" ng-if="orderCtrl.editMode"><input type="text" class="form-control" ng-model="orderCtrl.property"/></div>

Directive usage:

 <editable-text property="orderCtrl.order.coid" edit-mode="orderCtrl.editingView"></editable-text>

I'm not sure that we really need to pass edit-mode attribute.

Upvotes: 0

Views: 493

Answers (1)

Pankaj Parkar
Pankaj Parkar

Reputation: 136194

You should use bindToController: { ..scope properties.. } option here inside your directive to make sure that isolated scope properties should get bounded to controller this context.

Directive

orderApp.directive('editableText', function(){
    return {
        restrict: 'E',
        bindToController: {
            property: '=property',
            editMode: '=editMode'
        },
        controller: 'OrderDetailsController',
        controllerAs: 'orderCtrl',
        templateUrl: '/pages/editable-text.html'
    }
});

Template

<div class="col-xs-8" ng-if="!orderCtrl.editMode">
     {{orderCtrl.property}}
</div>
<div class="col-xs-8" ng-if="orderCtrl.editMode">
   <input type="text" class="form-control" ng-model="orderCtrl.property"/>
</div>

Note:- this above bindToController: { ..scope properties.. } option available for angular 1.4+ versions.

For Angular 1.3 > version & 1.4 > version you should use former way of doing it by having bindingToController: true to bind scope variable to controller context & do keep the varaibles inside scope: { ...props... }

scope: {
    property: '=property',
    editMode: '=editMode'
},
bindToController: true

Upvotes: 1

Related Questions