2

I am learning about creating custom angular directives, where I would like to use some two way data binding; however with no luck.

Idea is super simple: We have a list of people, where once I select any of them, I want to display selected person's name (detail) in my directive.

Before I paste a lot of code, here is my example plunker:
https://plnkr.co/edit/xQJAWcYcscOaaNs8VlAI?p=preview

Here is what I have done:
Created Main Controller:

(function() {
"use strict";
var controllerId = 'personController';
angular.module("app").controller(controllerId, ["$timeout", personController]);

function personController($timeout) {
    var vm = this;
    vm.name = "Janko";
    vm.people = returnPeople();
    vm.selectedPerson = {};
    vm.selectPerson = function (person) {
        //function to add a new Person
        vm.selectedPerson = person;
        console.log(vm.selectedPerson.name);
    };
}

function returnPeople() {
    return [
        {
            name: "Janko",
            surname: "Hrasko",
            age: 24,
            gender: "M"
        },
        {
            name: "Jozef",
            surname: "Mrkvicka",
            age: 26,
            gender: "M"
        },
        {
            name: "Janka",
            surname: "Kratka",
            age: 21,
            gender: "F"
        }
    ];
};
})();

Created Directive:

(function () {
"use strict";

var app = angular.module("app");

app.directive('personDetail', personDetail);
function personDetail() {
    return {
        scope: {
            person: "=person"
        },
        restrict: 'E',
        templateUrl: '/js/person/templates/personDetail.html'
    }
};
})();

**Created Person Detail Controller: **

(function() {
"use strict";

var controllerId = 'personDetail';
angular.module("app").controller(controllerId, ["$scope", personController]);

function personController($scope) {
    var vm = this;
    vm.person = $scope.person;
}
})();

Finally - person Detail.html

<div ng-controller="personDetail as vm">
  <h3>Selected Name:</h3>
  <h3>{{vm.person.name}}</h3>
</div>

Unfortunately, data binding is not working, even though I can see that the item has been selected. What am I doing wrong here?

Edit:
All of your answers have removed the ng-controller from my personDetail.html, however I would like to keep it (currently it only contains one minor binding, yet I want to add more functionality there such as button clicks etc).

Is it possible to keep the controller?

4 Answers 4

3

markup: <person-detail person="vm.selectedPerson"></person-detail>

function personDetailsController($scope) {
  var vm = this;
  //vm.person = $scope.person;// This will get executed only first time.
  //Every time you assigning different object to it. Not changing object.property
}

You can use controller as syntax as follows which also preserve two way binding.

 function personDetail() {
   return {
      scope: {
         person: "="
      },
      bindToController: true,
      controller:'personDetailsController',
      controllerAs: 'vm',
      restrict: 'E',
      templateUrl: 'personDetail.html'
    }
 };

Demo

Sign up to request clarification or add additional context in comments.

Comments

3

You need to pass the selected person to the directive. You have exposed the "person" variable in your directive, you need to pass the selected person to the directive. And also you don't need a controller for the controller.

Change your directive declaration like this:

<person-detail person="vm.selectedPerson"></person-detail>

Edited

Also remove the controller in your directive, there is no need for that extra controller.

<div>
  <h3>Selected Name:</h3>
  <h3>{{person.name}}</h3>
</div>

I have created a plunkr to demo the solution. You can see it here.

3 Comments

have you changed anything else except for the person=vm.selectedPerson? I have tried to implement it in my local solution, but it is still not working...yet the Plunk (which is 1-1 copy) is working :)
Yes, I have removed the extra controller that you are using in the directive. You can check my plunkr that I shared.
@RobertJ. did it help?
3

you were almost there. I updated your plunkr
In index.html you have to specify the object you'd like to bind to like so:

<person-detail person="vm.selectedPerson"></person-detail>

The personDetail.js file is not needed. And in personDetail.html you have to replace vm.person.name with person.name. By the way since angular 1.5 you are able to use angular-components which are somewhat easier to use.

Comments

2

The person you are binding to in directive should a attribute in element which you have not specified. So pass that as:

<person-detail person="vm.selectedPerson"></person-detail>

and in the directive template remove the mention of ng-controller="personDetail as vm" use it as:

<div>
  <h3>Selected Name:</h3>
  <h3>{{person.name}}</h3>
</div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.