Question

In my current project I have to deal with many types of Categories. Each category has to be rendered in a different way, and has different functionalities.

In order to achieve this, I created a Category factory which acts as a "base class" in my model. In this way, I can extend/override Category behavior (e.g, by defining a MultiCategory which contains subcategories).

The problem comes when I try to have each category type render differently: in order to do so, I defined a directive:

<div ng-repeat="category in data.categories" category="category"></div>

In my design, the directive would switch on category.constructor.name to decide how to render itself:

<div class="container" ng-switch="category.constructor.name">
    <div ng-switch-when="MultiCategory"></div>
    ....
</div>

However, when I tried to do this, AngularJS threw an error at me, because it doesn't allow constructor.name expressions. (Related to security)

I found a workaround by implementing a function

Category.prototype.getType = function() {
    return this.constructor.name;
}

The switch then becomes:

...ng-switch="category.getType()"...

See an example in this jsfiddle.

So far it's working ok, but I'm not really comfortable with this approach. It required me to pollute Category.prototype, and if there are security concerns in using constructor.name, I would like to address them.

So my question is: can anyone come up with a better approach?

EDIT:

Comments/answers focus on the use of ngSwitch, but that is not the issue raised by this question. I'd still have the same problem by using

ng-if="category.constructor.name"

The point is: What is the best approach to determine the type of my model objects that doesn't require restorting to constructor.name? Do I really need to pollute my model with a type property or a getType method?

Was it helpful?

Solution 2

Maybe it will help you to see how i'm doing it. I've a base-class called stdClass.

In your case i would do s.th. like:

var Category = stdClass.extend({
    constructor:function(attrs){
       this.attrs = attrs || {};
    },
    getType:function(){ return this.type; }
});

var CategoryA = Category.extend({ type:'A' });
var CategoryB = Category.extend({ type:'B' });

Now create new Models and push them to an array:

var collection = $scope.items = [];

var model = new CategoryA({name:'Peter'});
collection.push(model);

var model = new CategoryB({name:'Paul'});
collection.push(model);

And in your view:

<div ng-repeat="item in items">
    <div ng-if="item.type == 'A'">Category A: {{item.attrs.name}}</div>
    <div ng-if="item.type == 'B'">Category B: {{item.attrs.name}}</div>
</div>

Maybe this will help you. Do not hesitate to ask more... =)

OTHER TIPS

ng-switch is not the best tool for your case. It is intended for things like "tab-bars". In your case i would prefer

<div ng-repeat="category in data.categories">
    <ng-if="category.type == 'exampleTypeA'"></div>
    <ng-if="category.type == 'exampleTypeB'"></div>
    <ng-if="category.type == 'exampleTypeC'"></div>
    ...
</div>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top