I'm learning Angular 12 and I have some issues about the framework operation.
I've created a new project, added Bootstrap 5 and created some components.
When I nest a component inside another like this :
<div class="container">
<div class="row">
<div class="col-xs-12">
<h2>Mes appareils</h2>
<ul class="list-group">
<app-appareil [appareilName]="appareilOne"></app-appareil>
<app-appareil [appareilName]="appareilTwo"></app-appareil>
<app-appareil [appareilName]="appareilThree"></app-appareil>
</ul>
</div>
</div>
</div>
I don't understand why I still see the custom selectors in the browser inspector view :
Angular browser view
It breaks several things in my Boostrap style.
Did you know if it's possible to hide/remove these custom components of my browser view to get in this case only the <li> tags directly inside the <ul> instead of these <app-appareil> ?
Thanks :)
Change
#Component({
selector: "app-appareil"
})
to
#Component({
selector: "li[appAppareil]"
})
and then use it as
<ul class="list-group">
<li appAppareil [appareilName]="appareilOne"></li>
</ul>
By using an attribute selector we can avoid the wrapping component tag (which you cannot "remove"), and we preserve semantics of the DOM itself.
Likely to get better semantics you'd want to make further changes and use content projection, but that's unclear from the limited information and beyond the scope of the question anyway.
To make it the "Angular way", the approach needs to be changed.
Supposing that you have a collection of device names (appareilNames) returned from your component:
public get deviceNames(): Array<string> { ... }
The appropriate tags structure can be achieved as follows:
<ul class="list-group">
<li *ngFor="let deviceName of deviceNames"> <!-- iterate on each device name -->
<app-appareil [appareilName]="deviceName"></app-appareil> <!-- use each name to create a component with it -->
</li>
</ul>
Related
I know it can be achieved using Javascript by manually separate the slot elements and put them into the DOM tree but I wonder if it's supported within the box. Something like this:
<my-element>
<div slot="items">Item 1</div>
<div slot="items">Item 2</div>
<div slot="items">...</div>
</my-element>
And the template should be like this:
<div class="items">
<div class="item"> <!-- Should be 1 item per slot -->
<p>Something else</p>
<slot name="items"></slot>
</div>
</div>
Is this only possible using slotchange and populate the items by Javascript? Is there any better solution, without Javascript or with less Javascript? Maybe there is an element similar to slot that I am not aware of?
since all slot="items" will be slotted into <slot name="items"> only with the slotchange Event can the Component Author determine what happened.
Note: You do not populate the items, the default slotting mechanism does; you can only remove items after they are slotted; but then your HTML above needs more info on which Item needs to be slotted.
Then the question remains, Why use multiple slot="items" at all then?? If a slot can take 1 item, then only assign 1 item
Imperative Slots might help out: https://github.com/WICG/webcomponents/blob/gh-pages/proposals/Imperative-Shadow-DOM-Distribution-API.md
Update, I misunderdstood OPs question
All he needs to do is:
Create another Web Component: <slotted-item slot="items"></slotted-item>
I have around 300 components and I am adding embedding one common menu html, and I want to change url value with unique value.
here is my files:
common.menu.component.html
<div class="packages-menu">
<ul>
<li *ngFor="let allPkgs of packages; let i = index;" routerLinkActive="active">
<a routerLink="/nepal-package-{{i+startingNight}}n" class="packages-link" title="{{allPkgs.title}}">{{allPkgs.title}} </a>
</li>
</ul>
</div>
I want to change routerLink value while embedding in other component
common.menu.component.ts
#Component({
selector: 'packages-menu',
templateUrl: './common.menu.component.html',
providers:[PackagesServices]
})
other.component.ts
while embedding it I am passing data-val to get different value.
<packages-menu data-val="different value"></packages-menu>
<div class="hti-modrentitle">
<h1>{{pkg.title}}</h1>
</div>
I want to put **data-val** value in routerLink so I can have different url for all components.
Is that possible or any other way to do it. Please help
Let's say I have a list of links and I want each of them to change the DOM on the current page
using ng-click and templating, how would I do that?
Edit: I guess what I am trying to understand is how to move as much of the logic away from the .html file and into my app.js file. I'm a little new to JS and Angular and don't know where or how to pass "active" to choose what I'd like to place inside
For example:
<ul>
<li>
<h1>foo1</h1>
</li>
<li>
<h1>foo2</h1>
</li>
<li>
<h1>foo3</h1>
</li>
</ul>
<active></active>
Where the active element displays only what template is set to the active one.
ie; the template associated with foo1 is displayed, and then if foo2 is clicked the template for foo2 replaces foo1
I am not sure what is the implementation of <active>, but you can use ng-include to implement what you are expecting
<active ng-include='active'></active>
Now create a client side or server side template with the name which matches variable active defined on scope and corresponding template would get loaded
A template definition could be like
<script type="text/ng-template" id="foo1">
<!-- html template for foo here-->
</script>
See ng-include documentation.
You could use ng-show/ng-hide. Basically something like this.
<div ng-show="foo1">
<p> This will only show when foo1 is true on your scope.
</div>
<div ng-show="foo2">
<p> This will only show when foo2 is true on your scope.
</div>
<div ng-show="foo3">
<p> This will only show when foo3 is true on your scope.
</div>
Also if you're wanting to keep the logic of the active = 'foo1' just change up the logic in the ng-show. Usually you want to keep logic out of the view though, so move that to your controller.
I am trying to conditionally display a directive based on a boolean value stored in the parent scope. I can't figure out why the below does not work. By, "not work" I mean neither directives are displayed.
<ul class="nav navbar-nav pull-right" ng-switch="userIsAuthenticated">
<account-item item="accountMenuItem" ng-repeat="accountMenuItem in anonymousMenuItems" ng-switch-when="false"></account-item>
<account-item item="accountMenuItem" ng-repeat="accountMenuItem in authenticatedMenuItems" ng-switch-when="true"></account-item>
</ul>
Neither directives are shown even thought "userIsAuthenticated" is set to 'false' in my test case. If I add {{userIsAuthenticated}} above the directives 'false' is output as expected.
I've also tried this:
<ul class="nav navbar-nav pull-right" ng-switch={{userIsAuthenticated}}>
<account-item item="accountMenuItem" ng-repeat="accountMenuItem in anonymousMenuItems" ng-switch-when={{false}}></account-item>
<account-item item="accountMenuItem" ng-repeat="accountMenuItem in authenticatedMenuItems" ng-switch-when={{true}}></account-item>
</ul>
If I remove the conditional ng-switch-when attribute from either of the directives they will display. So I'm know the problem is my ng-switch.
Your usage of ng-switch works in this simplified demo, of course without your account-item directive:
http://plnkr.co/AppN8xmFeIwjaP631lj7
Without seeing the code for account-item, it is hard to guess what might be interfering with it. You might consider using ng-if to handle displaying one item or another.
<ul>
<div ng-if="!userIsAuthenticated">Content when not authenticated</div>
<div ng-if="userIsAuthenticated">Content when authenticated</div>
</ul>
Update
Also make sure you bind to an object property, instead of a primitive boolean. Like: user. authenticated
Since ngSwitchWhen has a priority of 800, you need to set a higher priority to your custom directive (i.e. account-item) in order for it to be compiled before being process by the ngSwitchWhen directive. E.g.:
.directive('accountItem', function () {
return {
...
priority: 900,
...
};
});
In the following code, users in an array of user objects, which have a name property in them:
$.template("listTemplate", "<ul><li>${name}</li></ul>");
$.tmpl("listTemplate", users).appendTo("#app");
My purpose is to generate a html similar to:
<div id="app">
<ul>
<li>Barney</li>
<li>Cartman</li>
<li>Sheldon</li>
</ul>
</div>
However, I'm stuck with:
<div id="app">
<ul><li>Barney</li></ul>
<ul><li>Cartman</li></ul>
<ul><li>Sheldon</li></ul>
</div>
Is there an elegant way to accomplish this directly with a jquery template, and somehow indicate to the templating engine that <ul> need not be repeated?