injecting dynamic html inside the components from index.html in angular 8 - javascript

I am working on a web app. which has magnolia as CMS. i am still new here but i will explain the scenario.
magnolia is providing the index.html which has reference of the components.But for some of those components it also provides some additional html content. this additional content has to be shown inside the particular component's template. refer following for better understanding.(remember this is inside the index.html)
<my-component>
<div> this division has to be shown inside the my component template.</div>
</my-component>
I have tried following approaches till now.
trying to use - this apparently does not work as i have learnt recently that the angular is not the master of root template(index.html). so ng-content never works. correct me if i am wrong.
using shadow dom view encapsulation. I am not expert in this, but setting viewencapsulation = shadowdom and defining slot inside the component template fulfills my purpose. The only issue with this approach is the scope of this shadow element. it will be inside the shadow root which has its own scope so no global styles are applied inside it. i had to import all the global css for each such component, which makes the main.js go crazy in size.
can someone please suggest me if there is any better or other solution to this problem?

Have you tried using Input() values for that component?
index.html
<my-comp [myInputs]="'My Input HTML <b>Content</b>'">
your receiving component…
<div [innerHTML]="myInputs"></div>

On my side, I use <ng-content></ng-content> inside the component where I want to put my dynamic content.
Ex:
<app-help-tool>
<span i18n="##pictoTable_helpPictoList">Click on a picto to see its description.</span>
</app-help-tool>
And in HelpToolComponent.ts:
<div
class="help_content"
*ngIf="this.isVisible && this.helpService.isHelpOn()"
[#showHideHelp]
(click)="showHideHelp()"
>
<ng-content></ng-content>
</div>
The result is to put the span content into the div of the component.

Related

Angular template not rendering

Right now I am creating a library (my-custom-library) and a project in which we'll use that library (called my-Project)
The requirement is, that within my-project I have to use my-custom-library, extended with templates, like this (my-project's app.component.html):
<my-custom-library>
<ng-template #myTemplate>
<div>Some static content for now</div>
</ng-template>
</my-custom-library>
The reason for this is, that in my-custom-library they want to have template-able components, where the template is given from the outside (in this case from my-project).
Within my-custom-library I'm supposed to access the given template(s) and pass them to the corresponding components. This I'm trying to achieve (my-custom-project's app.component.ts)
#ContentChild("myTemplate") myTemplateRef?: TemplateRef<any>;
(my-custom-project's app.component.html)
<ng-container [ngTemplateOutlet]="myTemplateRef"></ng-container>
My problem is, that the contentChild is always empty, the template never renders. The structure itself I think is working, since when I'm moving this same structure within just one project and use it there everything works fine, the contentChild gets its value and "my template" is rendered.
One more information, I don't know if its useful but my-custom-library is created like this (my-custom-library's app.module.ts):
export class AppModule {
constructor(private injector: Injector) {
const customElement = createCustomElement(AppComponent, { injector: this.injector });
customElements.define('my-custom-library', customElement);
}
}
What could cause this issue? Is it even possible to achieve this?
I had the same issue, Apparently ngTemplateOutlet does not work with angular elements. but you can try content projection without ngTemplateOutlet and it works fine.
e.g
<my-custom-library>
<div placeholder1></div>
</my-custom-library>
and you can define placeholder1 within your angular element (my-custom-library)
e.g
<div>
/*your angular my-custom-library code here */
/* the content you want to inject from outside of your angular elements*/
<ng-content select="[placeholder1]"></ng-content>
</div>
Note: you can also do nesting of your angular elements as well using this, but with this approach you have to make sure that ng-content is not affect by any ngif condition, because your angular element can project the content from outside but it can not regenerate projection based on your conditions. those conditions should be added from where you are projecting content.

Vue 2 - Styling HTML returned in a switch statement

I'm building a generic component supposed to receive various backend data. I wrote a switch. One condition is :
case 'Bases':
let bases = variant[tableName][colValue].map((base) => {
return `<div class="base b${base.strongestIndication}">${base.name}</div>`
})
return bases.join('')
I use v-html in my template, therefore in this case, we have 3 divs created, each with a class of "base" and then "b1", "b2", "b3". I can see on the webpage that these classes are properly set when I inspect the elements.
I've described in my style some rules for theses classes (mostly background-color, border-radius and so on), but they do not apply.
I'm guessing this might have something to do with the CSS being applied before these divs are created but I'm not sure of this.
What should I do to get these tags created by JS to be styled properly ?
(Also, I know using v-html can be dangerous, therefore if you have a better idea for this whole thing, I'm all ears)
There is no need to build the markup in component methods. Define it in template and bind the classes dynamically. Since you didn't post the api data structure, neither how you are using this snippet of code, I can only refactor the specific case.
<div
v-for="base in colValues"
:class="['base', `b${base.strongestIndication}`]">
{{base.name}}
</div>
Figured it out. For those wondering, switch statements returning html code aren't styled if the tag in your file is scoped. Unsure why, but removing scoped work. If you decide to do so, but unique class names, as these styles will spread all throughout the application !

Angular > How to use a content query to get an element inside an template outlet

In an Angular app, I've developed a reusable component whose responsibility to take care of rendering a wrapper around content provided by the parent component. The wrapper provides some layout and functionality that is required by multiple components (the parents). To accomplish this, I've adopted the "Component Composition" technique outlined in the following article which relies on the use of NgTemplateOutlet to enable the parent component to provide the content rendered inside the wrapper.
https://blog.bitsrc.io/component-reusability-techniques-with-angular-727a6c603ad2
This approach has been working well in a variety of situations but now I've come across a new situation where one of the parent components needs to use a content query to get an element inside the template outlet. I've been unsuccessful in using either the ViewChild or ContentChild decorators to get a handle on the element.
The following pseudo code outlines the basic approach I've attempted to take to date.
Reusable Element:
<div class="card">
<ng-container *ngTemplateOutlet="chart"></ng-container>
</div>
...
#ContentChild('chart', {static: false})
chart: TemplateRef<any>;
Parent Component:
<app-shared-component>
<ng-template #chart>
<div #top10Graph></div>
</ng-template>
</app-shared-component>
...
#ViewChild('top10Graph', { static: false }) private top10GraphContainer: ElementRef;
ngAfterViewInit(): void {
console.log(this.top10GraphContainer); // undefined
}
Is there any solution for using a content query for obtaining an element inside a template outlet such as I'm using here, or is another approach required?
The end goal (not demonstrated here) is to enable the parent component to render a data driven graph inside the template outlet.
I'm using Angular 10.
I think you get undefined because using ng-template is not yet rendered.
This code can work for you
<app-shared-component>
<ng-template #chart>
<div #top10Graph></div>
</ng-template>
<ng-container *ngTemplateOutlet="chart"></ng-container>
</app-shared-component>
Hope useful

Angular 4, use html without Component backing

I'm using Angular 4, and as of now my application follows the following pattern with
something.component.ts
something.component.html
something.component.css
However, I would like to have a raw html ("legal.html") file and reference it in the "something.component.html" view but I'm not sure about where to even start or what question to ask.
"legal.html" will also have to be bind to the parent controller too (something.component.ts).
Any help on getting something like this to work:
legal.html
<div>Hello</div>
something.component.html
<div>
I'm something
<legal>
</div>
is greatly appreciated.
What you are looking for is component.
You can simple create a new component using following command
ng g component legal
Then in legat.component.html file write your html then in your other html file you can simply refer to your code using selector tag
This link may be helpful
Angular component

In AngularJS, how can I nest variable child directive(s) inside a parent directive?

Introduction
For the project I am working on, I am trying to tackle a particular problem in the 'angular way', however I think I must be missing something because no matter what I try I continue to reach brick wall.
The crux of this issue is I am dynamically loading data from a backend that describes different components that are visible to the user. That's not the issue itself, but rather the issue of the particular & proper 'angular' way to turn a list of 'models' describing the components into actually rendered HTML.
Problem
What I am trying to create is basically the following:
Start off with a parent directive that uses ng-repeat for a scoped list called "models", which contains zero or more "components":
<parent-directive ng-repeat="model in models" model="model"></parent-directive>
The ng-repeat directive creates N copies of that original directive with different 'model' arguments (for each object in the $scope.models array).
// this is just for demonstrative purposes, it obviously looks different in source
<parent-directive model="child1"></parent-directive>
<parent-directive model="child2"></parent-directive>
<parent-directive model="child3"></parent-directive>
issue! => The parentdirective gets transformed into a specific child directive depending on data (in this case, called 'type') contained within the javascript object:
<parent-directive model="..."></parent-directive>
turns into
<child-directive-one model="..."></child-directive-one>
or
<child-directive-two model="..."></child-directive-two>
dependent on what the value 'model.type' is.
The child directive then renders into it's own custom HTML (outside the scope of this problem) using data passed to it. If we continued the example from above, that HTML should render into the following (hopefully):
<child-directive-one model="child1"></child-directive-one>
<child-directive-one model="child2"></child-directive-one>
<child-directive-two model="child3"></child-directive-two>'
Followed by (and this is outside the scope of the issue but just to see it through to the end) each directive rendering into its own HTML:
<div>in childDirectiveOne, text is: This is text contained inside child1</div>
<div>in childDirectiveOne, text is: This is text contained inside child2</div>
<div>in childDirectiveTwo, text is: This is text contained inside child3</div>
Source
I've been trying lots of different variations of things to try and get it to work (involving the link function, using $compile, etc), but this source is provided with all of those attempts stripped out. Here's the source I've developed so far:
removed source (was filled with errors). Solution that Scott helped me out with is below:
Conclusion
Thanks for any advice in advance.
Update:
Solution exists here (thanks again to Scott).
I'm not sure exactly why you can't just have a single directive, however something like the following might work. Instead of repeating the parent directive you just pass in the models and have that directive repeat and create each of the child directives.
<parent-directive the-models="models"></parent-directive>
Parent directive template:
<div ng-repeat="model in models"....>
<child-directive ng-if="YOUR CONDITION"></child-directive>
<child-directive2 ng-if="YOUR CONDITION"></child-directive>
</div>

Categories