1

Update: See Jim Schubert's answer for the fix. See This SO for why this matters.

I have three ways to display dynamic text in an AngularJS directive and they are all giving me different issues. I would like to pass in a value via an attribute that will display in my template. My template is actually a file but I converted this simplified JSFiddle to use template show my issue.

You can see in the code below or in the JSFiddle that I have 3 examples.

  1. Repeat use of the first example will only show the last use for every use on the page. This allows for spaces, underscores, ect.
  2. This allows for repeat use on the page, but does not allow for spaces, underscores, ect.
  3. This allows for both repeat use and spaces, underscores, ect. The issue with this is I do not expect the object to be the same for every use of the directive. I.E. I want to pass in the text and value from any object, text could be text={{ruhOh}} or text={{iLikePeanutButter}}. I could map it, but that is additional overhead.

What I expect Allow repeat use of directives with dynamic text and different text on each directive. Allow underscores, spaces, ect.

<div ng-controller="MyCtrl">
    <!--Always displays the last use for every use-->
    <ntt-form-text text="OperationsA" value="3"></ntt-form-text>
    <ntt-form-text text="OperationsB" value="3"></ntt-form-text>

    <!--three will display here-->
    <ntt-form-text-three text="Operations" value="5" obj="obj"></ntt-form-text-three>

    <!--spaces, underscores, dashes, ect cause display errors, tried both single and double quotes-->
    <ntt-form-text-two text="Operations A" value="5"></ntt-form-text-two> <!-- displays {{text}} -->
    <!--<ntt-form-text-two text="Description_2" value="5"></ntt-form-text-two>--> <!-- displays blank -->
    <!--<ntt-form-text-two text="ASDF-2" value="5"></ntt-form-text-two>--> <!-- displays -2 -->

    <!--three will fail to display here due to failure in two-->
    <ntt-form-text-three text="description" value="6" obj="obj"></ntt-form-text-three>
</div>

var myApp = angular.module('myApp',[]);

myApp.directive('nttFormText', [
    function () {
        return {
            restrict: 'E',
            //scope: false,
            template: '<div>Text: {{text}}</div>',
            link: function (scope, element, attrs) {
                scope.text = attrs.text;
                scope.value = attrs.value;
            }
        };
    }])

myApp.directive('nttFormTextTwo', [
    function () {
        return {
            restrict: 'E',
            scope: { text: '=', value: '=' },
            template: '<div>Text: {{text}}</div>'
        };
    }])

myApp.directive('nttFormTextThree', [
    function () {
        return {
            restrict: 'E',
            scope: { text: '=', value: '=', obj: '=' },
            template: '<div>Text: {{text}} Value: {{value}} Spaced Word: {{obj.spacedWord}}</div>'
        };
    }])

myApp.controller('MyCtrl', function ($scope) {
    $scope.obj = { spacedWord: "hello world!" };
});
Community
  • 1
  • 1
JabberwockyDecompiler
  • 3,318
  • 2
  • 42
  • 54

1 Answers1

1

http://jsfiddle.net/gh9qwo1L/7/

I think the problem you're having is using scope bindings. From https://docs.angularjs.org/guide/directive:

  • To bind to the attribute in <div bind-to-this="thing">, you'd specify a binding of =bindToThis
  • use &attr in the scope option when you want your directive to expose an API for binding to behaviors.

The missing binding from the documentation is @, which will bind to a value. I've updated your fiddle to make one of your directives work as you're expecting. For example:

myApp.directive('nttFormTextThree', [
    function () {
        return {
            restrict: 'E',
            // NOTE: '=' means two way binding, '@' means bind to a value.
            scope: { text: '@', value: '=', obj: '=' },
            template: '<div>Text: {{text}} Value: {{value}} Spaced Word: {{obj.spacedWord}}</div>'
        };
    }])

   // usage
   <ntt-form-text-three text="Operations" value="5" obj="obj"></ntt-form-text-three>

The @ allows you to bind text to be displayed as text.

Here's how you'd use it the way you had it (text: '='):

myApp.directive('nttFormTextThreeEx', [
    function () {
        return {
            restrict: 'E',
            scope: { text: '=', value: '=', obj: '=' },
            template: '<div>Text: {{text}} Value: {{value}} Spaced Word: {{obj.spacedWord}}</div>'
        };
    }])

// in your parent scope:
$scope.operations = 'Operations on scope';

// template usage bound to scope
<ntt-form-text-three-ex text="operations" value="5" obj="obj"></ntt-form-text-three-ex>

// template usage bound to text
<ntt-form-text-three-ex text="'Wrapped in quotes'" value="5" obj="obj"></ntt-form-text-three-ex>
Joseph Yaduvanshi
  • 20,241
  • 5
  • 61
  • 69