Dynamically transcluding multiple elements in Angular

Angular 1.5 introduces the option to multi-transclude.

An interesting feature would be the ability to transclude a variable number of items into a directive and specify their names and positions at a later stage (for example, in the link/compile functions).

For instance, I envision being able to achieve something like:

//Demonstration of directive usage
<multi-slot-transclude-example>
<transclude1>TEST1</div>
<transclude2>TEST2</div>
<transclude3>TEST3</div>
<transclude4>TEST4</div>
.... any number of dynamic items ...
</multi-slot-transclude-example>

//Sample directive that dynamically transcludes multiple items
angular.module("multiSlotTranscludeExample", [])
    .directive("directiveName", function(){
    return {
        restrict: 'E',
        transclude: {
            't1': '?transclude1',
            't2': '?transclude2',
            //I want this list to be capable of dynamic definition (e.g., in the link function)
        },
        template: '<div ng-repeat="n in transcludedElementList">'
        + '<div ng-transclude="t{{n}"></div>'
        + '</div>'
        };
})

It's worth mentioning that when implementing a multi-transclude in a directive, you need to know beforehand the number of items to be transcluded.

Is there a way to achieve a similar functionality either through the link function or using a workaround while maintaining the current transclusion capabilities?

Answer №1

It appears that Angular lacks a simple method to achieve this without being intrusive.

Nevertheless, with a minor adjustment, it is possible to make it work.

The key is to modify the transclusion slot logic within angular.js:

...

var slots = createMap();

$template = jqLite(jqLiteClone(compileNode)).contents();

// A small change for dynamic transclusion capability
if (directiveValue === 'dynamic') {
  directiveValue = $parse(templateAttrs.transcludeDynamic)();
}

if (isObject(directiveValue)) {

  // If there are transclusion slots,
  // gather them, compile them, and save their transclusion functions
  $template = [];

...

By doing this, we can define the transclusion options in the consumer of the component like this:

<my-custom-component transclude-dynamic="{testSlot: 'test', testSlot2: 'test2'}">
  <test>something to transclude</test>
  <test2>then another slot content to transclude</test2>
</my-custom-component>

In the component, we activate dynamic transclusion:

...
selector: 'myCustomComponent',
template: template,
transclude: 'dynamic',
bindings: {
  transcludeDynamic: '<'
}

It's important to note that we also bind the transclusion information, allowing us to use ng-repeat, ng-if, and other directives on it.

For instance:

<div ng-repeat="(slot, name) in $ctrl.transcludeDynamic">
  <div ng-transclude="{{slot}}"></div>
  <hr>
  <div>something else</div>
</div>

PR: https://github.com/angular/angular.js/pull/14227

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

Developing a jQuery loop

I am in the process of creating a function that will change the background color (color A), box color (color B), and text color (color A) when a user clicks on the refresh button. I have already defined an array called 'colors', but I am struggli ...

"Although all error messages are functional in Postman, they are not appearing correctly on the frontend client

I am currently developing a website using React and Node. While testing my register and login functionality in Postman, I encountered an issue where the error message for login (e.g., user doesn't exist, username or password incorrect) is not displayi ...

Expanding the size of one div causes the surrounding divs to shift positions

I am currently working on creating a row of divs that expand when hovered over by the mouse. I have managed to achieve this functionality, but now I want the expanding div to cover its neighboring divs partially, without affecting their sizes or moving the ...

Optimizing with react and mobX: What You Need to Know

I am new to React and MobX and have been studying various tutorials on using both together. Currently, I am working on creating a form where users can select a product through autocomplete functionality using react-select. Once a product is selected, the i ...

Error: The property 'open' is not defined in the mdMenu object

Encountered a bug while working with angular-material design... When using md-menu, if a sub menu item is opened (as shown in the image) and then hovering over a non-subMenu item (menu item), it throws an error "Cannot read property 'open' of nul ...

When using AngularJS in conjunction with Karma-Jasmine, it is important to note that the functions verifyNoOutstandingExpectation() and verifyNoOutstandingRequest() may not

There is an unresolved HTTP request that needs to be flushed. When I use the following code afterEach(function(){ $httpBackend.verifyNoOutstandingExpectation(); $httpBackend.verifyNoOutstandingRequest(); }); The code functions correctly and I ...

Display a loading message using jQuery Dialog when the page is loading

I have a button that triggers a jQuery Dialog box to open. $( "#dialog" ).dialog({ autoOpen: false, title: 'Contract', height: 450, width:1100, modal:true, resizable: true }); $( ".btnSend" ).click(function() { var id=$(this).a ...

The challenge of Webpack errors arising from sharing a project between two different machines

My project is saved in a Google Drive folder and runs smoothly on one of my machines. However, when I try to compile the code on another machine, I encounter multiple errors all related to loading images. The error message below is just one example (others ...

To effectively delete the <li> element using JavaScript, make sure to eliminate the associated array object as well

I am in the process of designing a compact landing page that will randomly select a city from user input to determine the next trip destination. When the user types in the city name into the input field, everything functions correctly - a new list element ...

Updating a database seamlessly via a dropdown menu without having to refresh the entire webpage

Before we proceed, please take a look at the following code: $(document).ready(function() { $("#alternatecolor [type=button]").each(function() { $(this).on('click', function() { btnObj = $(this); rowId = $(this).attr("rowId") ...

Is it considered beneficial to use Observable as a static class member?

Lately, I have been diving into a new Angular project and noticed that the common way to share state between unrelated components is by using rxjs Subject/BehaviorSubject as static members within the class. For instance: export class AbcService { privat ...

GET request body parameters are not defined

Can anyone help me with retrieving the parameters of a GET request? I've tried various methods but everything keeps logging out as 'undefined': GET // Looking for a list of Players $scope.find = function() { $scope.players = Players.qu ...

What is the best way to display a unique modal on every tab?

I'm facing an issue where I am attempting to trigger a modal on each tab item, however the modal only opens on the initial tab. Clicking on any other item results in the modal opening on the first tab instead. Additionally, when I add new items, I am ...

Chat Bot - EmbedMessage

JavaScript is still very new to me and I find the actual code quite challenging to grasp. However, I do have one specific question - how can I display the "cahbResponses" in a MessageEmbed? Despite consulting the Discord JS guides on MessageEmbeds, I' ...

Error: Unable to call topFrame.window.changeSelectedBarStyle because it is not a valid function. What could be causing this

This function is called changeSelectedBarStyle: function changeSelectedBarStyle(tdId){ $("#menuTable td").each(function(index){ if(this.id == tdId){ $(this).removeClass("menuPanel"); $(this).addClass("menuPanelSelected" ...

Enabling Event bus suggestions for Typescript: A step-by-step guide

Hello, I've encountered an issue while attempting to add types for the TinyEmitter library. Specifically, I need to define two methods. First: addEventListener(e: string, (...args: any[]) => void): void; Second: emit(e: string, ...args: any[]): vo ...

Issue with Cloud Code function preventing data from being saved

After successfully testing this code in Angular and getting the correct responses in console.log, I decided to migrate it to cloud code. Since the function manipulates data in the user table, I had to use the master key and implement it in cloud code. Howe ...

Issue with data updating in Angular rxjs with share, map, and filter functions

After gathering search criteria from a form, I have developed a method that retrieves an observable of talents. fetchTalents(searchCriteria) { return this._allUsers$.pipe( tap((talents) => console.log(talents)), map((tale ...

Learn how to hide a bar after clicking the "I agree" button with the help of Bootstrap

click here to see imageIs there a way to make that bar disappear once the user clicks "I agree"? I've searched through Bootstrap documentation but couldn't find a solution. Please assist. Below is the code snippet: <div id="cookie-message" cl ...

Setting up React Router in a nested directory with a flexible route structure

As a newcomer to react router, I am seeking guidance on setting it up in a specific scenario. Imagine we have a PHP application running on 'http://www.example.com'. Within this setup, there is a react application located at 'http://www.examp ...