0

I'm new in Angular and I would like to know if it's possible to bind in a directive a part of an expression ?

Currently without a directive I do this (it's working) :

<div>
    <ui-select ng-model="myModel" search-enabled="false">
        <ui-select-match>
            <span>{{'myLabelPrefix.' + $select.selected.myLabelCode | translate}}</span>
        </ui-select-match>
        <ui-select-choices repeat="item in (myList | filter: $select.search) track by item.myLabelId"
            position="down">
            <span>{{'myLabelPrefix.' + item.myLabelCode | translate}}</span>
        </ui-select-choices>
    </ui-select>
</div>

What I want to do :

My template :

<div>
<ui-select ng-model="ngModel" search-enabled="false">
    <ui-select-match>
        <span>{{labelPrefix + $select.selected.labelCode | translate}}</span>
    </ui-select-match>
    <ui-select-choices repeat="item in (list | filter: $select.search) track by item.labelId" position="down">
        <span>{{labelPrefix + item.labelCode | translate}}</span>
    </ui-select-choices>
</ui-select>
</div>

My directive :

app.directive('selectField', function() {
return {
    replace: true,
    templateUrl: 'app/components/select-field/select-field-view.html',
    restrict: 'E',
    require : 'ngModel',
    scope: {
        ngModel: "=ngModel",
        labelPrefix: '=',
        labelId: '=',
        labelCode: '=',
        list: '='
    },
    link: function(scope, el, attr) {
        console.log(attr);
    }
};
});

My HTML tag :

<select-field ng-model="myModel"
    label-prefix="'myLabelPrefix'"
    label-id="myLabelId"
    label-code="myLabelCode"
    list="myList">
</select-field>

So, how to bind label-prefix, label-id, label-code and list attributes with directive attributes ?

Thanks

Daniel
  • 9,491
  • 12
  • 50
  • 66
Nan
  • 63
  • 1
  • 9

2 Answers2

0

Yeah You can do it. By adding transclude option in your directive and need to add ng-transclude to html directive

    angular.module('transcludeExample', [])
   .directive('pane', function(){
      return {
        restrict: 'E',
        transclude: true,
        scope: { title:'@' },
        template: '<div style="border: 1px solid black;">' +
                    '<div style="background-color: gray">{{title}}</div>' +
                    '<ng-transclude></ng-transclude>' +
                  '</div>'
      };
  })

http://plnkr.co/edit/?p=preview

Siddharth Pandey
  • 649
  • 1
  • 9
  • 21
  • I have nothing inside my select-field tag, so for what is it useful to use ng-transclude? – Nan Mar 01 '16 at 16:07
0

My preferred approach to solvin your problem would be to use a custom filter wrapping the translate functionality and passing the prefix there. The implementation would look like this:

angular.module('xy').filter('translateWithPrefix, ['$filter', function($filter){
    return function(input, prefix) {
        if(!input) return null;
        if(!prefix) return $filter('translate')(input);
        return $filter('translate')(prefix + input);
    };
}]);

And the usage would look like:

<ui-select-match>
    {{ $select.selected.labelCode | translateWithPrefix: labelPrefix }}
</ui-select-match>

Alternative: Based on the accepted answer on the following link, you could also use the suggested compile directive to recompile the expression in eg. ui-select-match: angular ng-bind-html and directive within it

The template used by your directive should look similar to this:

<ui-select-match>
    <span ng-bind="{{labelPrefix}} + $select.selected.labelCode | translate" compile></span>
</ui-select-match>

I have not tried this approach though.

Update

As for binding the labelId used track by expression... What we're looking for is obviously an expression similar to this: which needs to be compiled once and only then processed by the ng-repeat directive. However, this is often not really required. Depending on how complex your items are, I'd suggest either dropping the "track by" completely (sacrificing some performance) or replacing it with "track by $index", thus getting rid of this problem.

Update 2

As for the labelCode - I assume that you want to pass some string key eg. 'name' to the directive and then use this key to lookup property on each item. First, I'd change the binding of labelCode from '=' to '@'. Then within your directive use it as item[labelCode] and you should be good to go.

Community
  • 1
  • 1
Michal Filip
  • 870
  • 8
  • 9
  • Ok thanks, I used the filter, it's great! But how you do for binding labelId and labelCode with item.labelId and item.labelCode. Moreover my model is not bind to but why? – Nan Mar 01 '16 at 19:38
  • The second tip using the compile directive should help in this case. What we're looking for is obviously an expression similar to this: `` which needs to be compiled once and only then processed by the ng-repeat directive. However, this is often not really required. Depending on how complex your items are, I'd suggest either dropping the "track by" completely (sacrificing some performance) or replacing it with "track by $index", thus getting rid of this problem. – Michal Filip Mar 03 '16 at 10:03
  • It's ok by removing the labelId (track by item.labelId), but I still have the problem with the labelCode. Moreover repeat="item in link track by {{item.labelId}}" is not working, I get this error : `code`Error: [$parse:syntax] errors.angularjs.org/1.4.7/$parse/… `code` `code`TypeError: Cannot read property 'source' of undefined`code` – Nan Mar 15 '16 at 22:25
  • Angular doesn't support that expression out of the box. That's what the mentioned `compile` directive attempts to do. Also, one more update to the answer. – Michal Filip Mar 17 '16 at 07:50