Angular ng-container equivalent in vue.js - javascript

In Angular there is a tag called ng-container used like so
<ng-container *ngIf="false">this wont be shown</ng-container>
now as per the angular docs
The Angular is a grouping element that doesn't interfere with styles or layout because Angular doesn't put it in the DOM.
Now this is really handy in angular since there are often times I would like to group a set of html elements without using a <div></div>
For example
<div class="flex-div">
<ng-container *ngIf="true">
<img src="cool-img" alt="awesome">
<h1>Cool Title</h1>
<p>Cool Text</p>
</ng-container>
<ng-container *ngIf="false">
<img src="not-so-cool-img" alt="awesome">
<h1>Not So Cool Title</h1>
<p>Not So Cool Text</p>
</ng-container>
</div>
here I have a div that has a position of flex on it and also rules about what the elements inside do..
Now If I wrapped the elements in a normal div it will break my flex styles but with the ng-container it contains my elements but is not rendered to them DOM
Is there an equivalent in Vue??

You could use conditional grouping on a template as mentioned in the docs here. The template will serve as an invisible wrapper.
<div class="flex-div">
<template v-if="true">
<img src="cool-img" alt="awesome">
<h1>Cool Title</h1>
<p>Cool Text</p>
</template>
<template v-if="false">
<img src="not-so-cool-img" alt="awesome">
<h1>Not So Cool Title</h1>
<p>Not So Cool Text</p>
</template>
</div>

Related

Add Component or Directive to HTML template received from the server

Let's say an endpoint returns this HTML:
<div data-type="section">
<div data-type="section-header">
Section 1
</div>
<div data-type="section-body">
Lorem ipsum
</div>
</div>
Above template will be stored in component property sections. In an Angular app we will append this HTML to the page via <div class="sections-container" [innerHtml]="sections"></div>.
Before appending HTML template to innerHtml, is it possible to add component or directive to the HTML template received from the backend?
For example we have HighlightDirective, which will set background to yellow and we want to apply it to data-type="section-header" element, so that HTML template will look like this:
<div data-type="section">
<div data-type="section-header" appHighlight>
Section 1
</div>
<div data-type="section-body">
Lorem ipsum
</div>
</div>
Will Angular automatically recognize the appHighlight directive and add it to the component tree? Or it's necessary to hydrate this HTML template?
The solution that I have found it is wrapped HTML into anonymous component and handle string from BE. Then compile that and looks like everything is ok.
Stackblitz example

Change the root element of a component

VueJS allows only one root element per component. In most case that's fine to wrap the component inside a div tag but it can sometimes cause unexpected behaviors.
For instance, when using Bootstrap, if you put a div between two elements (like <b-row> and <b-col>), the layout get totally broken.
Many other elements in the framework needs to follow a specific order and that's why having one root element could be problematic.
Is there a way to dynamically set the root element?
To illustrate what i'm saying, take a look at this example:
If a have a component my-h1 like this:
<template>
<div>
<h1>Hello world</h1>
</div>
</template>
which get called here:
<div id="my-app">
<my-h1 />
</div>
The code above will output:
<div id="my-app">
<div>
<h1>Hello world</h1>
</div>
</div>
How can i get this output:
<div id="my-app">
<p>
<h1>Hello world</h1>
</p>
</div>
and at another place, this one:
<div id="my-app">
<a>
<h1>Hello world</h1>
</a>
</div>
(I know these tags doesn't make any sense, it's only for the purpose of this exemple)
I hope you see what i mean. Still have one root element, but setting it to be different, with a prop or something else :)
Just use the special <component> component which allows you to choose the component dynamically:
MyComponent.vue
<template>
<component :is="is" v-bind="props">
Hello world
</component>
<template>
export default {
props: ['is', 'props'],
}
Usage is like so:
<my-component is="div"/>
<my-component is="p"/>
With slots you will have to replace the entire component, which I don't think you want.
The other solution will be to pass a type property to your component and do a switch (I don't know if it is compliant with vue general philosophy)
But here is an example about what I was thinking:
<template>
<template v-if="type === 'div'">
<div>
<h1>Hello world</h1>
</div>
</template>
<template v-else-if="type === 'a'">
<a>
<h1>Hello world</h1>
</a>
</template>
<template v-else-if="type === 'p'">
<p>
<h1>Hello world</h1>
</p>
</template>
<template v-else>
<i>
This is a default
<b>ITALIC TEXT</b>
</i>
</template>
</template>
<script>
export default {
props: {
type: String
}
};
</script>
Then you call your component
<component type="div|p|a|whatever"/>

Projecting ngFor template in <ng-content> isn't working

I'm working on an Angular 4 project and I'm stuck on a problem regarding templates.
Let me explain it better.
I have two components in my project:
SectionCompontent.ts
HomeCompontent.ts
These are the relative HTML templates
section.compontent.html
<div class="section">
<div class="cards">
<ng-content></ng-content>
</div>
</div>
home.compontent.html
<section>
<div *ngFor="let card of cards">
<span>{{card.title}}</span>
</div>
</section>
When I run this project, I expect to see the rendered content of *ngFor projected inside SectionComponent where <ng-content> is located.
Unfortunately, this is what I see on the DOM instead of <ng-content>:
<!--bindings={}-->
I added some static HTML tags like <p> and <h1> and they allowed it to work.
Can you help me solve this problem?
Thanks in advance.

Angular 2 component without selector tag in DOM

I want this:
<div *ngIf="...">div 1...</div>
<div *ngIf="...">div 2...</div>
<div *ngIf="...">div 3...</div>
But I don't wanna repeat the *ngIf, so I created my component <my-component>, with this template:
<div>div 1...</div>
<div>div 2...</div>
<div>div 3...</div>
And I put *ngIf in my component tag: <my-component *ngIf="...">
The problem is that Angular 2 is putting the <my-component> tag in the DOM, and I don't want it.
For anyone who knows ASP.NET WebForms, I want a component in Angular 2 that works like <asp:PlaceHolder> control...
To answer your question, you can also do this...
#Component({
selector: '[my-component]'...
<my-component *ngIf="..."</my-component>
// becomes this in the dom
<div my-component _nghost...>
There is also ng-container for this purpose.
<ng-container *ngIf="something.is.there">
<div class="here">
Hello
</div>
</ng-container>
// DOM: => <div class="here">Hello</div>
You can solve this by using CSS only, just set my-component as display: contents,
my-component {
display: contents;
}
As stated on display: contents documentation, this causes to appear as if the component were direct children of the element's parent.
Use equivalent expanded *ngIf notation with template tag:
<template [ngIf]="check">
<div>div 1...</div>
<div>div 2...</div>
<div>div 3...</div>
</template>

Vue.js fragment instance

I seriously don't know, why the fragments is the problem.
<template>
<div id="page">
</div>
<div class="some">
</div>
</template>
[Vue warn]: Attribute "id" is ignored on component "div"
You need to wrap the contents of your template in another div. When it comes to render it, it needs the single root element to replace
<template>
<div>
<div id="page">
</div>
<div class="some">
</div>
</div>
</template>
Vue v3 now supports multi-root templates. Your code should work out-of-the-box.
https://v3-migration.vuejs.org/new/fragments.html

Categories

Resources