sam
sam

Reputation: 598

angularjs directive binding name attribute to template element

I am trying create a wrapper directive over select and I am trying to assign the 'name 'attribute to the select

directive

    <form name=myform>
          <selectformfield label="Select Orders" id="id_1" name="orderselection"
            selectedval="obj.order" options="Orders" />
    </form>

I have my directive defined as

mainApp
    .directive(
            'selectformfield',
            function() {
                return {
                    restrict : 'E',
                    transclude : true,
                    scope : {
                        label : '@',
                        id : '@',
                        selectedval : '=',
                        options : '=',
                        name: '='
                    },
                      template : "<select class='form-control'     ng-model='selectedval' name='{{name}}' ng-options='item as item.name for item in options' required><option value=''>-- select --</option></select>"

                };
            });

I am trying to access the select's name attribute through myform in the controller something like console.log($scope.myForm.orderselection) and I get undefined

If I hardcode the name in the directive then I am able to access the attribute console.log($scope.myForm.orderselection)

I am missing anything here. Do I have to do any post compile or something ?

Upvotes: 8

Views: 17572

Answers (2)

Khanh TO
Khanh TO

Reputation: 48972

Accessing the DOM directly in $scope is bad practice and should be avoided at all costs. In MVC structure like angular, instead of accessing the DOM (view) to get its state and data, access the models instead ($scope). In your case, you're binding the name of your directive to the orderselection property of your parent scope. Also notice that a form is an instance of FormController. The form instance can optionally be published into the scope using the name attribute. In your case, you create a new property on the parent scope.

You could try accessing the name like this if you're in your parent scope:

console.log( $scope.myform.orderselection );

Or if you're in your directive scope.

console.log( $scope.name);

Because your scope directive name property binds to your parent scope orderselection property, you need to assign a value to your parent scope property or it will be undefined. Like this:

$scope.myform.orderselection = "orderselection ";

If you need to do validation inside your directive, since you already bind the name attribute with the orderselection. You could do it like this:

template : "<select class='form-control' ng-attr-name='{{name}}'  ng-disabled='[name].$invalid' .../>

Upvotes: 0

mortalapeman
mortalapeman

Reputation: 1425

Khanh TO is correct in that you need to setup your name correctly when trying to access to through your isolated scope. Here is a working example of what I believe you are trying to accomplish. I've added comments to the code where I've changed what you had.

plunker

Javascript:

var app = angular.module('plunker', [])

.controller('MainCtrl', function ($scope, $log) {
    $scope.model = {
        person: {
            name: 'World'
        },
        people: [{
            name: 'Bob'
        }, {
            name: 'Harry'
        }, {
            name: 'World'
        }]
    };
})

.directive('selectformfield', function ($compile) {
    return {
        restrict: 'E',
        replace: true, // Probably want replace instead of transclude
        scope: {
            label: '@',
            id: '@',
            selectedval: '=',
            options: '=',
            name: '@' // Change name to read the literal value of the attr
        },
        // change name='{{ name }}' to be ng-attr-name='{{ name }}' to support interpolation
        template: "<select class='form-control' ng-model='selectedval' ng-attr-name='{{name}}' ng-options='item as item.name for item in options' required><option value=''>-- select --</option></select>"
    };
});

HTML:

<body ng-controller="MainCtrl">
    <p>Hello {{ model.person.name}}!</p>
     <form name='myForm'>
          <label for='orderselection'>Say hello to: </label>
          <selectformfield label="Select Orders" id="id_1" name="orderselection"
            selectedval="model.person" options="model.people"></selectformfield>
       <p ng-class='{valid: myForm.$valid, invalid: myForm.$invalid }'>The form is valid: {{ myForm.$valid }}</p>
       <p ng-class='{valid: myForm.orderselection.$valid, invalid: myForm.orderselection.$invalid }'>The people select field is valid: {{ myForm.orderselection.$valid }}</p>
    </form>
  </body>

CSS:

.valid {
  color: green;
}

.invalid {
  color: red;
}

Upvotes: 5

Related Questions