2

I'm writing a directive that consists of an inline editor. When there is no value the edit box will appear. When there is value a regular span will appear.

This is the template chunk of the directive.

template: function (element,attrs) {

    if (1 === 2) {
        return "<div class='true'>{{product.title}}</div>";
    } else {
        return "<div class='false'>{{product.title}}</div>";
    }

}

The above code works, but the condition will be based on the model value received, I passed, ngModel, previously but it didn´t work:

require: '?ngModel',

template: function (element,attrs,ngModel) {

    if (ngModel.$modelValue !== null) {
        return "<div class='true'>{{product.title}}</div>";
    } else {
        return "<div class='false'>{{product.title}}</div>";
    }

}

HTML:

<div inline-editor ng-model="product.title"></div>

How do I get an AngularJS directive to load a different template based on a model value?

EDIT: Thanks everyone for your answers!, I took your comments, now I have the following code. Working for me until now, I will continue working on it.

return {
    restrict: "A",
    require: '?ngModel',
    link: function (scope, element, attrs, ngModel) {

        if (!ngModel) return;       

        //Formatter
        function writeElement (value) {

            var template;

            if (value !== null) {
                template = "<span>" + value + "</span>";
            } else {
                //template for false
            }

            element.replaceWith(template);
        }

        ngModel.$formatters.push(writeElement);

   }
Guillermo
  • 1,493
  • 3
  • 16
  • 35

2 Answers2

3

There are some problems with your code:

  • You cannot put ng-model on a div tag.
  • directive's template function signature is function(tElement, tAttrs) { , basically it runs during the compile phase and the ngModelController is not available yet.
  • You refer an outer scope variable {{ product.title }} inside your directive which couples your directive with the outer scope.
  • You don't need to use 2 classes ( true / false )

From ngModel docs:

The ngModel directive binds an input,select, textarea (or custom form control) to a property on the scope using ngModelController, which is created and exposed by this directive.

From $compile docs:

template

replace the current element with the contents of the HTML. The replacement process migrates all of the attributes / classes from the old element to the new one. See the Directives Guide for an example.

You can specify template as a string representing the template or as a function which takes two arguments tElement and tAttrs (described in the compile function api below) and returns a string value representing the template.

An example of how you can do it:

a plunker: http://plnkr.co/edit/UPbLXoucVCQXvPmm6BuZ?p=preview

Directive:

app.directive('inlineEditor',function($compile){
  return {
    scope: {
      model: "=ngModel"
    },
    require: 'ngModel',
    compile: function(tElm,tAttrs) {
      var editor = angular.element("<div ng-class='{showEditor: model}'>{{model}}</div>");
      var linkFn = $compile(editor);
      return function (scope,elm,attrs,ngModel){
        linkFn(scope);
        elm.after(editor);
      }      
    }
  }
})

css:

.showEditor {
  border: 1px solid red;
  height: 100px;
}

html:

<input inline-editor ng-model="product.title">
Community
  • 1
  • 1
Ilan Frumer
  • 32,059
  • 8
  • 70
  • 84
  • "You cannot put ng-model on a div tag". This isn't accurate: you can certainly put an ng-model on a div tag. You might want to do this when creating a custom form control, as mentioned by the docs you've quoted. – Michal Charemza Jan 27 '14 at 19:47
0

This logic does not belong in the template function, I think, but in the template itself:

template:
  '<div class="true"  ng-if="product.title == null">{{product.title}}</div>' +
  '<div class="false" ng-if="product.title != null">{{product.title}}</div>'
musically_ut
  • 34,028
  • 8
  • 94
  • 106
  • This is a very bad idea, `inline-editor` assumes `product.title` is on the outer scope. You can not reuse this directive. – Ilan Frumer Jan 27 '14 at 15:44
  • @IlanFrumer This was an example derived from original code. It deals with only the question of how to pick _a template_. – musically_ut Jan 27 '14 at 15:51