ui-sref-active on an abstract state - javascript

I have these routes:
.account /:email
.account.home /:email
.account.personal /:email/personal
.account.settings /:email/settings
.account is an abstract state and .account.home is the default state that it would go onto.
Now if I have this link, with an ui-sref-active to add a class when it is navigated, I would do something like
<a ui-sref-active='active' ui-sref='.account.home({email: account.email})'></a>
the right element is set with an active class when it is clicked (which is was expected), but if I then clicked on .account.personal it is removed since it is not a child of .account.home but a child of .account
How can I set the ui-sref-active to remain active to the <a></a> above even I selected a different route under it? But I cannot link it to the abstract state since we cannot navigate to an abstract state?

you have to use ui-sref-active like ng-class
<a
ui-sref-active='{"active": ".account({email: account.email})" }'
ui-sref='.account.home({email: account.email})'
>
the important part is this:
{"active": ".account({email: account.email})" }
which tells ui-router to set the active class when the current state is .account({email: account.email}) so it is now looking at the abstract state .account and not .account.home

Related

Web Components - Multiple elements per slot

I'm working on new web-components and ran into some issues concerning slots.
I have an outer container-component with a "main-slot" inside, in which multiple elements should be inserted (into the same slot). However, it is only possible to add one element per named slot.
My question: is there a way to add multiple elements to one named slot? Like shown here:
<own-container>
<own-element slot="main"></own-element>
<own-element slot="main"></own-element>
<own-element slot="main"></own-element>
<own-element slot="main"></own-element>
</own-container>
There is also imperative <slot>
super().attachShadow({
mode: 'open',
slotAssignment: 'manual' // imperative assign only
})
But! you get Named slots OR Imperative slots, on one Web Component
To mimic named <slot>, assigning content to the same named <slot>
you probably need the Mutation Observer API
addendum
You can have multiple elements per slot:
<component-with-slots>
<H1 slot="title">Web Components are great!</H1>
<h2 slot="title">A bit hard to master</h2>
<b slot="title">But Great!</b>
</component-with-slots>
<script>
customElements.define('component-with-slots', class extends HTMLElement {
constructor() {
super()
.attachShadow({mode:'open'})
.innerHTML="<slot name='title'></slot>";
}
});
</script>
Nope. It is not possible for named slot. The trick is to have a wrapper div element to wrap your lightDOM.
<own-container>
<div slot="main">
<own-element></own-element>
<own-element></own-element>
<own-element></own-element>
<own-element></own-element>
</div>
</own-container>
If the presence of additional div causes styling problem, then you can use new contents type of display box.
div {
display: contents;
}
The display: contents causes an element's children to appear as if they were direct children of the element's parent, ignoring the element itself. However, note that it can cause accessibility issues.

Stimulus nested (child) targets

Is it possible (and is it appropriate) to use nested/child targets of parent target?
For example i have “N+“ menu items, each item (wrapper) contain link and list.
I could add data-main-menu-target="menuItem" to each of parent items and then iterate over them in controller loop using this.menuItemTargets.forEach(...)
But what's the best practice to find menu-item-link and menu-item-list for each menu-item target on each loop iteration?
In general i could add targets also for those elements, e.g. menuItemLink & menuItemList, but how then i could select them from parent menuItem target, Is it possible to do something like menuItemTarget.find(this.this.menuListTarget)?
To visualise the structure is the following:
data-controller="main-menu"
data-main-menu-target="menuItem"
data-main-menu-target="menuLink"
data-main-menu-target="menuList"
....
data-main-menu-target="menuItem"
data-main-menu-target="menuLink"
data-main-menu-target="menuList"
....
How then select "menuLink" for certain "menuItem" target on each loop?
You could structure your controller so that you have one menu controller that gets used on both the root menu and also the sub-menus within them. This could be recursively accessed from whatever is deemed to to be the root.
Example Code
In the HTML below we have a nav which contains ul for a menu, each child should be an item target.
Within each item we may have a link target OR another sub-menu which itself is another menu controller and the pattern continues.
<nav>
<ul class="menu-list" data-controller="menu" data-menu-target="root">
<li data-menu-target="item">
<a data-menu-target="link">Team Settings</a>
</li>
<li data-menu-target="item">
<ul data-controller="menu">
<li data-menu-target="item">
<a data-menu-target="link">Members</a>
</li>
<li data-menu-target="item">
<a data-menu-target="link">Plugins</a>
</li>
<li data-menu-target="item">
<a data-menu-target="link">Add a member</a>
</li>
</ul>
</li>
<li data-menu-target="item">
<a data-menu-target="link">Invitations</a>
</li>
<li data-menu-target="item">
<a data-menu-target="link">Cloud Storage Environment Settings</a>
</li>
</ul>
</nav>
In our controller we first determine if this controller's instance is the root, simply by checking this.hasRootTarget.
Controllers only get access to their 'scoped' elements so the root can only 'see' the children outside of the nested data-controller='menu'.
We need to use setTimeout to wait for any sub-controllers to connect, there may be a nicer event propagation way to do this.
You can access a controller on an element via the getControllerForElementAndIdentifier method.
From here we can determine the menu structure as an array of either a link target OR a nested array which itself will contain the sub link targets.
We can use the Node.contains method to map through each item and see what links are 'contained' within it.
This approach could be refined to get you the structure you need to work with.
class MenuController extends Controller {
static targets = ['item', 'link', 'root'];
connect() {
if (this.hasRootTarget) {
setTimeout(() => {
// must use setTimeout to ensure any sub-menus are connected
// alternative approach would be to fire a 'ready' like event on submenus
console.log('main menu', this.getMenuStructure());
});
}
}
getMenuStructure() {
const links = this.linkTargets;
return this.itemTargets.map((item) => {
const child = item.firstElementChild;
const subMenu = this.application.getControllerForElementAndIdentifier(
child,
this.identifier
);
const menuLinks = links.filter((link) => item.contains(link));
return subMenu ? subMenu.getMenuStructure() : menuLinks;
});
}
}
Notes
We are accessing the DOM via the firstElementChild and this may not be the way we want to do things in Stimulus, but you could simply add another target type of 'sub-menu' to be more explicit and follow the pattern of finding the 'link' within each item this way.
A reminder that you cannot put the data-controller="menu" on a data-menu-target="item" as this will remove the item from the parent scope. As per the docs on scopes.
that element and all of its children make up the controller’s scope.
Answer from another conversation,
A) For menuLink and menuList, you handle it by yourself: use CSS
classes, and then use normal selectors. So, once you've used the
menuItem target to find the menuItem you want, you would then do
menuItem.querySelector('.menu-link'). Not a Stimulus solution, but
it's pretty simple and it's nice to be able to "back out" and do
things manually if you need to.
B) I'm not sure what your overall Stimulus controller is meant to do,
but it's possible that there should be a menu-item controller that
lives on the menuItem target. Depending on what you're trying to
accomplish, that could replace the main-menu controller or, more
likely (because I'm assuming you are doing some "work" on the top
level main-menu where you want to be aware of all of the "items"), in
addition to the main-menu controller. With this setup, your main-menu
controller could loop over the menuItem targets and, in each one,
directly use its underlying controller instance - even calling methods
on it. This is not something I showed on the tutorial, but it's not an
uncommon pattern: you would expose the "controller instance" of the
"menu-item" controller on its element - e.g.
https://www.betterstimulus.... (the big difference in that example is
that both of the controllers are on the same element - so adjust
accordingly).
(c) weaverryan

React Library : How to set up a class specifity

Ok, so, i have a component that takes a className as a prop, but the component itself comes with an default style.
className={`${
props.classNameStyle ? `${styles.defaultButtonStyle} ${props.classNameStyle}` : styles.defaultButtonStyle
}
If className prop exists, it should put as classes both the default class and the class passed as prop, and otherwise, to put just the default class. It works, but, i want the class passed as prop to have a bigger CSS specifity than the default button, because, let's say that we have :
.defaultButtonStyle { background-color:red }
and
.classNameStyle { background-color:blue } (this is the class from props)
it should make the background color blue, but in the browser's console, the classNameStyle it's cut, and the background-color is set to the default button style. I don't want to use !important, because that's gonna be annoying for the user. Any ideas?

How to apply Style to custom component content in Angular?

I am trying to apply styling to a child of a custom component.
Selector:
<custom-component-example></custom-component-example>
Inside custom-component-example.html:
<button>
<ng-content></ng-content>
</button>
If I were to use style like this:
<custom-component-example style="color: green">some text</custom-component-example>
Or like this:
<custom-component-example [ngStyle]="{'color': green}">some text</custom-component-example>
The button text will not get green. The styling could be anything (for example font-weight or size or anything really).
I have also tried the solution to this topic:
Best way to pass styling to a component
But that also does not apply to the child element (button in the example above).
How do I pass any given styling and apply it to the child element, in the case of the example, how would I pass styling (through the custom-component-example selector) and apply it to the button and the button's text?
Thanks in advance.
You should never alter the child style from the parent, instead here is what you should do :
Apply a class to the parent (let's say green-button).
In the child's css you need to check that does my parent has a class green-button, if yes then it should change it's color.
In the child's css file ->
:host-context(.green-button) button{
color : green
}
You should not transfer styles from parent to child essentialy because it spoils the ViewEncapsulation goodness that Angular is proud of.
Here is some refrence . : Link
Also, the child component should be responsible for how does it button looks. The parent should be concerned about itself. In the future, if you will have two children to your parent, it will be difficult to manage what style to pass to what child.
Using this method, altering style is not only easy but also manageable.
Upvote and mark as solved if I was able to help.Cheers.
You need to pass the style property to the child component using the #Input() like
Your child component HTML code should look like
<div [className]="tableCss">
</div>
Your child component ts file code shoule look like
#Input() tableCss: string;
Your Parent component should look like
<app-list [tableCss]="'table-responsive table-borderless table-grid mt-4 border-top border-primary'"></app-list>
Try to change styles into [styles]
custom-component-example.html
<button [ngStyle]="styles">
<ng-content></ng-content>
</button>
custom-component-example.ts
#Input() styles: any = {};
Use,
<custom-component-example [styles]="{color: green}">some text</custom-component-example>
If you would like to use input and styles without deep selectecting of css like that:
a > b > c {
color: green;
}
Change this class to this:
class CustomComponentExample {
#Input() styles;
}
Set styles for this input:
<custom-component-example [styles]="{'color': green}">some text</custom-component-example>
Use this property in your component:
<button [ngStyle]="styles">
<ng-content></ng-content>
</button>
Try this:
Add a class on that component into your template file like this example bellow. (class='toggle-button').
<custom-component-example class="toggle-button"> Button name </custom-component-example>
Use ::ng-deep to your scss file for styling this class and add !important to that parameter.
::ng-deep .toggle-button { .switch-btn {
width: 80px !important;
height: 40px !important;}}
*"switch-btn" class is a class into the parent component.

Animate (Expand,collapse) child component along With parent component [Angular5]

I want to achieve this(Ref. attached image) in Angular 5
There Two components User-layout and role
User-Layout Component has been used at the start of Role component.
I am able to Expand and collapse the Parent component with animations but unable to to do the same simultaneously for the child component.
Any way to trigger animation on child component from the parent component.
For communication between child component and parent component you can use #Input, #Output and EventEmitter.
If you want to pass data from parent to child you can simply do it using #Input as below:
First you need to import Input into your child component using
import { Component, Input } from '#angular/core';
Then you need to declare an #Input variable in your child component
export class ChildComponent {
#Input() parentVariable: string;
}
Then while using the child component in you parent you need to specify the varible as an attribute as below
<child-component [parentVariable]="parentData"></child-component>
You should have a parentData declare in your parent component whose changes will reflect in the child component #Input variable parentVariable.
Thats all you need to do to and you need to animatation code which will trigger on the change of parentVariable variable.
Hope this helps!!!!
Take a look at animateChild() method.
Excerpt from the blog post posted by the #angular/animations author, Matias Niemelä, about animateChild()
Now what about the situation when there is an element in the application that has an animation ready-to-go, but a parent animation runs instead? Is there a way that the parent animation can dictate when the child animation runs, how long it runs for or if it doesn't run at all?
[...]
If these animations trigger at the same time then the parent animation will always win and the child animation will be skipped. However, using animateChild we can have the parent animation query into the child and tell it when it's allowed to animate:
Sub Animations With animateChild
component.html
<!-- do these two guys animate at the same time? -->
<div [#parent]="parentVal">
<div [#child]="childVal">
...
</div>
</div>
component.animations
trigger('parent', [
style({ transform: 'translate(-100px)' }),
animate('500ms',
style({ transform: 'translate(0px)' })),
query('# child', animateChild())
]),
trigger('child', [
style({ opacity:0 }),
animate('0.5s', style({ opacity:1 }))
])

Categories

Resources