6

In my project, I have a small div that has 3 options "food", "drinks", "social". These are tied to a scope variable "$scope.option" on "AppController".

I have a series of ng-switch statements:

<div ng-switch on="option">
<div ng-switch-when="food">
<fooddirective></fooddirective>
</div>
<div ng-switch-when="drinks">
<drinksdirective></drinksdirective>
</div>
<div ng-switch-when="social">
<socialdirective></socialdirective>
</div>
</div>

Note that whatever option is selected, the food, drink, or social, these only take up half the page so they are all surrounded by "AppController". My intent is to be able to "Dynamically load directives" into the page. Is there a way I can get rid of the need to have to explicitly write "<socialdirective></socialdirective>" or maybe even get rid of all of the ng-switch? Or is there some better alternative? It feels like it could get very messy if I have say 20 or 30 of these options (i.e. food, drinks, social, games).

If I know the name of the directive in advance, say "food", "drinks", "social". Is there some way I can do something like:

<div ng-switch on="option">
   // code that interprets option's variable (i.e. food), appends the text "directive" after, and dynamically/lazily add it in and remove it so it behaves like an ng-switch
</div>

I am not sure if it is possible, but am looking for any better alternative to what I am doing now. Any examples of a revised way of doing is great.

Rolando
  • 58,640
  • 98
  • 266
  • 407
  • this sounds like a job for a `$routeProvider`. There are many useful tutorials available via google. – kasoban Aug 04 '15 at 15:31
  • A routeProvider chages content for the entire page given my understanding I am looking for just changing a small component of my page. – Rolando Aug 04 '15 at 15:31
  • 1
    It changes content for a `ng-view`. that may just be a smaller content section, and keep header/navigation etc intact. – kasoban Aug 04 '15 at 15:32
  • Using "ng-view" as an example, I would have say 3 ng-views on my page. – Rolando Aug 04 '15 at 15:33
  • No, one ng-view, and depending on your route the routeProvider will inject the fitting view in its place. – kasoban Aug 04 '15 at 15:33
  • Can use nested views with ui-router, or can use a dynamic `ng-include` whose source is determined by scope variable – charlietfl Aug 04 '15 at 15:33
  • @charlietfl 's suggestion might be more fitting if you don't want to touch the route. I suggested that because it seemed you wanted to emulate that behaviour. – kasoban Aug 04 '15 at 15:35
  • @ksoban, the limit of having one ng-view is why I avoid using routeProvider, I do not have a single route that dictates all the content in ng-view. Only "subsections"/"subviews" change based on how the user interacts. – Rolando Aug 04 '15 at 15:35
  • @charlietfl Would be forever grateful for any sample that applies to what I am trying to do. – Rolando Aug 04 '15 at 18:53
  • http://stackoverflow.com/questions/18976255/how-do-i-dynamically-build-an-ng-include-src easy web search for `angular dynamic ng-include` – charlietfl Aug 04 '15 at 18:58
  • In your stackoverflow post, it looks like it uses ng-repeat to add everything. I want to show food, drinks, or social (one at a time). How does a user event like "clicking on the option food" that sets the scope variable options change the content that is ng-included? From what I know, you need something like a bunch of 'ng-ifs' to have ng-include change. – Rolando Aug 04 '15 at 19:02
  • @Rolando the ´ng-repeat´ was just what the OP wanted. The point is it shows a method to include something dynamically by interpreting a variable/expression, which seems to be what you want to do. – kasoban Aug 05 '15 at 07:50
  • @kasoban My only concern with ng-repeat is I read somewhere performance i bad and use is discouraged because of overhead? – Rolando Aug 06 '15 at 17:50
  • Read again, you don't need ng-repeat. I can try and assemble an answer later maybe – kasoban Aug 06 '15 at 17:57

3 Answers3

1

If those directives have a lot of functionality in common, to me it seems that the best alternative would be to implement a new directive, say optiondirective, that encapsulates this behavior. This way you would just insert that directive on the html with the chosen option as the attribute, the ng-switch or whatever resolution mechanism you end up using would be hidden in the template of that directive, and the common functionality would be implemented in that directive's controller. That doesn't help you get rid of the hideous part, but at least you will get to re-use a greater portion of the implementation and modularize your code.

downhand
  • 395
  • 1
  • 9
  • 23
1

You can use UI router to accomplish this:

--index.html

<body>
  Top Level
  <div ui-view></div>
</body>

--optionsPage.html

<select ng-options="option.name for option in data.availableOptions track by option.id" ng-model="data.selectedOption"></select>
<div ui-view></div>

In the options page, you will make the select options generate ui-sref links to each type of directive you want to display. Child states will only change the ui-view of their parent state, so you can easily route to the correct directive.

Then you define your routes as such:

 .state('options.food', {
      templateUrl: "partials/options.food.html"
    })
    .state('options.drinks', {
      templateUrl: "partials/options.drinks.html"          
    })

Then you can define the directive in each of those HTML files.

(Much of this code is just taken from the Angular and UI-Router code examples, but hopefully you can see what you need to do.)

UI Router - https://github.com/angular-ui/ui-router

Andy Poquette
  • 400
  • 6
  • 15
  • The important thing here is the ui-router instead of ngRoute. The ui-router supports nested states. Thereby it can do a lot more than just change the whole page. –  Aug 18 '15 at 18:32
  • @ChristopherSchröder Absolutely. In my (admittedly limited) experience, UI-Router should just be what you use for routing with Angular. It works very well. – Andy Poquette Aug 18 '15 at 19:29
0

WARNING: I am not giving you a complitely working answer.. just want to give you an idea on how to do it.

you can create another directive which wraps the original one

.directive("wrapper", function(){
return {
  scope: {'option': @},
  template: '<' + option + 'directive>' + '</' + option + 'directive>'
}
})

and then call it like

if this does not work you will need to compile the html in your like function like below

      var tmpl = '<' + option + 'directive>' + '</' + option + 'directive>'
       element.html(tmpl );
       $compile(element.contents())(scope);

that should definitely do it

harishr
  • 17,807
  • 9
  • 78
  • 125