Search code examples
angularjsangularjs-scopeangular-directiveangularjs-templates

How merge expressions in custom directives Angularjs


I break my head try to resolve this problem. Suppose that I have this custom directive:

app.directive("selectInput",function($compile){
return {
    restrict: "E",
    templateUrl: 'js/angular-app/test.html',
    scope: {                
        formName:'=',
        inputName:"=",
        nameInput: "@",
        ngModel: "=",
    },
    transclude: true,
    replace: true,
    link: function(scope, element, attrs, ctrl) {   
        ...             
    },
}});

Here my templateurl test.html

<div
class="form-group"
ng-class="{'has-error has-feedback': formName.inputName.$invalid}"> 
<input type="text" name="{{nameInput}}" ng-model="ngModel"/></div>

And the call

<form name="form" class="simple-form" novalidate>
<select-input 
    form-name="form"                       
    input-name="fClase"            
    name-input="fClase"
    ng-model="inputmodel">
</select-input></form>

The problem is in test.html template, the expression formName.inputName.$invalid not work, I try {{formName}}.{{inputName}}.$invalid and nothing, also I try change the params in directive definition for &, @ ... =?.

I have not been able to merge this expressions, I appreciate any help.

Update, fix the problem (Thanks to Joe Enzminger):

At the end I change the directive by this:

app.directive("selectInput",function($compile){
return {
    restrict: "E",
    templateUrl: 'js/angular-app/test.html',
    scope: {           
        inputName: "@",
        ngModel: "=",
    },
    require: ["^form"],
    replace: true,
    link: function(scope, element, attrs, ctrl) {  
        scope.form = ctrl[0]; 
        ...             
    },
}});

Note the form attr as ctrl.

The template test.html

<div
class="form-group"
ng-class="{'has-error has-feedback': form[inputName].$invalid}"> 
<input type="text" name="{{nameInput}}" ng-model="ngModel"/></div>

Here change formName.inputName.$invalid by form[inputName].$invalid

And finally the call

<form name="form" class="simple-form" novalidate>
<select-input        
    input-name="fClase"   
    ng-model="inputmodel">
</select-input></form>

I hopefully useful


Solution

  • Here is an alternative implementation that might clarify how things actually work.

    The changes:

    Don't inject $compile (you don't use it)

    No transclude: true (you aren't using transclusion)

    scope: {} - we create an empty isolate scope so that our template will work and we can isolate the directive scope from the parent scope.

    require: ["ngModel", "^form"] - we want to require ngModel on the element and require that the element is embedded in a form. These will be delivered to the link functions ctrl parameter.

    <div
    class="form-group"
    ng-class="{'has-error has-feedback': form[model.$name].$invalid}"> 
    <input type="text" ng-model="model.$modelValue"/></div>
    
    <form name="form" class="simple-form" novalidate>
    <select-input 
        ng-model="inputmodel">
    </select-input></form>
    
    app.directive("selectInput",function(){
    return {
        restrict: "E",
        templateUrl: 'js/angular-app/test.html',
        scope: {},
        replace: true,
        require: ["ngModel", "^form"],
        link: function(scope, element, attrs, ctrl) {  
            //give our directive scope access to the model and form controllers
            $scope.model = ctrl[0];
            $scope.form = ctrl[1];          
        },
    }});