Ways to dynamically change templates within AngularJS

I've encountered a challenge with Angular that I can't seem to solve on my own. I have a news page that will be filled with various types of news, such as weather updates and breaking news. Each piece of news has its own unique template.

My Angular controller utilizes AJAX to fetch the news in JSON format, and I'm using ng-repeat to display this news on the user's screen. Additionally, I'm employing a directive for this purpose. The issue arises when a news item brought in by AJAX looks like this:

news: {
    title: "sdijfdslfkndc",
    template: "default_template.html",
    ....
}

And in the ng-repeat loop:

<div ng-repeat="info in news">
    <info-directive template="info.template"></info-directive>
</div>

I want the infoDirective to utilize the correct template specified in the current news item. The problem is that the info.template attribute is being treated as a String rather than an object.

If anyone has any insights or suggestions on how to address this issue, I would greatly appreciate it!

Goodbye for now!

PS: Just to give you a glimpse of my infoDirective:

app.directive('infoDirective', function() {
    return {
            restrict: 'E',
            scope: {
              template: '='
            },
            templateUrl: template
    };
});

Answer №1

When creating a directive, the templateUrl attribute can be set as a function that takes in two parameters: element and attributes. This function should return a string representing the URL of the template to be used for the element. By doing this, different templates can be displayed based on the attributes passed to the directive.

app.directive('infoDirective', function() {
    return {
            restrict: 'E',
            templateUrl: function(element,attributes){
                switch(attributes.template){
                     case "template1":
                     return "template.html";
                     //and so on
                }
            }
    };
});

Alternatively, a more simplified version can be implemented like this:

app.directive('infoDirective', function() {
    return {
            restrict: 'E',
            templateUrl: function(element,attributes){
                    //if you want to specify the templateURL
                    //directly in the attribute.
                    return attributes.template;
            }
    };
});

Answer №2

addresses your specific issue. For instance:

and here is the reference:

https://github.com/exampleuser/angular-template-dynamic

In the realm of JavaScript, everything is considered a String - even so-called JS "Objects"! Nonetheless, you have more flexibility when working with objects compared to pure strings. Remember this: HTML / CSS / JS all treat content as strings. So, if you encounter issues with non-object strings in JS, there are various solutions available. You can instantiate JS objects using "new ObjectName();" or opt for interpreting HTML code like this:

app.directive('contentItem', function ($compile) {
var imageTemplate = '<!-- Your image template here -->';
var videoTemplate = '<!-- Your video template here -->';
var noteTemplate = '<!-- Your note template here -->';

var getTemplate = function(contentType) {
    var template = '';

    switch(contentType) {
        case 'image':
            template = imageTemplate;
            break;
        case 'video':
            template = videoTemplate;
            break;
        case 'notes':
            template = noteTemplate;
            break;
    }

    return template;
}

var linker = function(scope, element, attrs) {
    scope.rootDirectory = 'images/';

    element.html(getTemplate(scope.content.content_type)).show();

    $compile(element.contents())(scope);
}

return {
    restrict: "E",
    link: linker,
    scope: {
        content:'='
    }
};
});

As mentioned earlier, there are several approaches to achieve your goal, but this method stands out as effective.

Answer №3

Here is a solution that could help you with your issue:

Check out this answer on Stackoverflow

You can also view the Plunkr example directly:

Plunkr Example

app.directive('myDirective', [function(){

return {
    template: '<div ng-include="getTemplate()"></div>',
    restrict: 'E',
scope: {template: '='},
link: function(scope, element, attr, ctrl) {
  var baseURL = 'templates/myDirective.'

  scope.getTemplate = function(){
      baseURL = "" //ignore this line
      return baseURL + scope.template + ".html"
    };
}
};
}]);

Answer №4

To improve your code organization, consider creating separate directives for different types of news. For example, have a directive for weather news and another for flash news. Each directive will have its own template, and you can inject the link function of your directive as if it were a service.

angular.module('newsModule', []).factory('link', function () {

  return function (scope, element, attrs, ctrl) {/*some logic here*/}; 

}).directive('flashNews', ['link', function (link){
  return {
            templateUrl: 'flash-news.html',
            link: link
  };
}]).directive('weatherNews', ['link', function (link){
  return {
            templateUrl: 'weather-news.html',
            link: link
  };
}]);

Use ng-repeat to loop through the news items based on their type:

<div ng-repeat="info in news">
    <div ng-if="info.type.weather">
      <weather-news></weather-news>
    </div>
    <div ng-if="info.type.flash">
      <flash-news></flash-news>
    </div>
</div>

Answer №5

Here is my solution to the issue at hand :

app.directive('information', function() {

return {
    restrict: 'E',
    scope: {
          data: '=',
    },
    link: function(scope) {
          scope.template = scope.data.template;
    },
    template:"<div ng-include='template'></div>"
};
});

Therefore

<div ng-repeat="data in news.news">
    <information data="data"></information>
</div>

Answer №6

Thank you to everyone for your input, but there's a little issue that I'm facing...

Every time I try to do this

<div ng-repeat="info in news">
    <info-directive template="info.template"></info-directive>
</div>

The problem arises when the info.template is treated as a String and I'm unable to access the value of the variable in my directive which is:

app.directive('infoDirective', function() {
    return {
        restrict: 'E',
        templateUrl: function(element,attributes){
                console.log(attributes.template);
                return attributes.template;
        }
    };
});

Even if I try using variables like $index or using {{ }} to manipulate variables into strings, nothing seems to work... For example, if I include template="{{info.template}}" in the info-directive, I end up with {{info.template}} instead of default_template.html in the templateUrl...

Any thoughts on how to solve this?

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Arrange a JavaScript map based on its values and ensure that a specific field index remains at the top position

I'm sure this question may seem simple to some, but as a JavaScript novice, I couldn't find the answer myself. Here is the code snippet I'm working with: Let map = new Map<String,String> map.set('0', select) map.set('1&a ...

Tips for modifying the HTML generated on the server side before it is rendered on the client side in Quasar

Just starting out with Vue.js and looking to implement Vue I18n. However, I'm facing an issue setting the locale on Vue I18n and also setting the HTML lang attribute to the same locale. The challenge is that I can't access the document object in ...

Issue with uncaught exceptions in promise rejection test

I am experiencing an issue with the following code: function foo(){ bar().catch(function(){ //do stuff } } function bar(){ return promiseReturner().then( function(result){ if(_.isEmpty(result)){ throw "Result is empty"; ...

Testing a custom Angular directive that encapsulates the functionality of SlickGrid

Currently, I am working on testing an angular directive that acts as a wrapper for slickgrid. 'use strict'; describe('Unit: Grid Directive', function() { var $scope; var element; beforeEach(module('grid')); beforeEac ...

Disregard the ng-blur event for specific elements

In my search feature, I have a suggestion box that appears below the search field when I start typing. I want the suggestion box to disappear when I click outside the search field, and also be able to click on a suggestion to perform a search. <input n ...

The map and its multiple markers are not showing up

I am attempting to display multiple markers on a Google map. Everything is working fine in two scenarios: When I display ONE marker When I write the GPS coordinates of different markers I have a database that contains longitude and latitude values. I wan ...

I am looking to remove identical innerText values from two arrays using JavaScript

Is it possible to use JavaScript to remove the "added" className of an element with the same innerText when the delete button (.btn-wrap>li>button) is clicked? <div class="table"> <ul> <li class="added">l ...

Using JavaScript to open a window in ASPX page

When I use the code below to open a new window and receive a success message, I also want to close the current window. However, I am encountering an error: Error: newwindow is not defined var value = getQueryStrings(); var cust_id = value["cust_id ...

What is the process for linking a script file to code in AngularJS using Sublime Text?

Attempting to code the sample program below in AngularJS using Sublime Text. Have already added the angular package to Preferences. However, when providing the src for angular as "angular.min.js", the code does not work; it only works when using "https://c ...

Troubleshooting issues with ember-data's belongsTo relationship

I am facing an issue with the model I have: Whenever I make a call to this.store.find('history'); A request is sent to http:://www.example.com/api/histories/ and I receive the following JSON response: { "tracks":[ { "id":83, ...

How can you spot the conclusion of different lines that refuse to remain in place?

Currently, I am facing a jquery issue that has left me stumped. The website I am working on is structured as follows: <div class="Header"></div> <div class="main"><?php include('content.html'); ?></div> <div clas ...

Exploring Objects in jQuery using JSON Data

The following JSON data is provided: {"Name":"bb", "age":"10"} After searching extensively on the internet, most of the answers assume prior knowledge of the keys "Name" and "age", resulting in references like j.Name and j.age. My objective is to itera ...

Using default language in Next.js internationalization: a step-by-step guide

I've been immersing myself in the Nextjs internationalization documentation for the past two days. My goal is to have support for two languages: en, fa. I also want to be able to switch between them with URLs structured like this: https://example.com ...

Creating HTML documents for AngularJS using Grunt

We are in the process of creating a website using AngularJS, and we want to ensure that search engines can easily index our content by having static HTML files for each page. Our website is relatively small, with only about 10-20 pages in total. I am won ...

"Using Jest to specifically test the functionality of returning strings within an object

Attempting to run a jest test, it seemed like the issue was with the expect, toBe section as I believed that the two objects being compared (data, geonames) were exactly the same. However, upon closer inspection, they turned out to be different. The struct ...

Implementing AJAX to Access a PHP File Across Multiple Web Pages

I devised a personal framework for myself. I implemented an ajax script on each page of my website by including a single PHP file in every webpage. Here is the script I added to my add.php file: function demo(str) { if (str.length==0){ ...

Vertical positioning offset of jQuery UI selectmenu in relation to buttons on this line

When creating a form, I like to place control elements in a line such as a button, select box, and checkbox for a logical layout. However, after incorporating jQuery UI, I noticed a strange vertical alignment issue with the select box. For reference, here ...

The Functional Components array is not correctly adding the props content

I'm facing an issue with adding an array of <TokenFeed/> functional components to the <Feeds/> component. The problem arises when I try to use the onClick() event handler to pass text to my <App/>, as it doesn't behave as expect ...

Toggle the field on and off using HTML and JavaScript from the bottom

My goal is to enable two fields in a row by clicking on "activate1", while the other fields remain unchanged. Similarly, I want to activate the other two fields by using "activator2" and so on. There should be three activators at the bottom solely for acti ...

Using Jquery for Multiple Submission Buttons

I am having an issue with two buttons in my form that are supposed to submit the form to different PHP files. However, when I click on the buttons, nothing happens and I can't seem to figure out what's wrong. HTML: <form id="sform" name="sfo ...