Condionally apply CSS to element in Aurelia - javascript

I have an array of items and I want to apply style class to an element which has my customname.
The style is not applying for any element. How can apply style based on condition?
var items =["one","two","three"];
<li repeat.for="item of items" class="${item == 'one'? 'someclass':''}">${item}</li>

Here's an example: https://gist.run?id=ed73adef9c634efbfc4dd109a68ec2c2
app.html
<template>
<h1>${message}</h1>
<ul ref="ul">
<li repeat.for="item of items" class="${item == 'one' ? 'someclass' : ''}">
${item}
</li>
</ul>
<h4>Resulting HTML:</h4>
<pre><code>${debug}</code></pre>
</template>
app.js
export class App {
message = 'Hello World!';
items = ["one","two","three"];
get debug() {
return this.ul.outerHTML;
}
}

Related

document.querySelector in Angular

I have a list where each li has unique data-id.
<ul class="list">
<li class="list__el"
*ngFor="let item of cars"
data-id="{{ item.id }}">
</li>
</ul>
In JS I would wrote
let myLi = document.querySelector(`.list__el[data-id="${item.id}"]`)
How to correctly rewrite it for Angular?
Use #ViewChildren and a template reference such as #listItem.
#Component({
template: `<ul class="list">
<li #listItem class="list__el"
*ngFor="let item of cars"
data-id="{{ item.id }}">
</li>
</ul>`
})
export component MyComponent implements AfterViewInit {
// Note that the parameter here relates to the #listItem in the template.
#ViewChildren('listItem')
public listItems!: QueryList<ElementRef<HTMLLIElement>>
public ngAfterViewInit() {
console.log(
this.listItems.find(itm =>
itm.nativeElement.getAttribute('data-id') === 'my-element-id'
)
)
}
}

Angular ngFor li html element set style

<ul class="days">
<liclass="day" *ngFor="let day of currentDays; let i = index"(click)="setStyle()">
{{day}}
</li>
</ul>
My question is how to add style to exactly specified element in list, when i use ngClass styles are added to all elements? It posible using method add pass reference to element and set style?
You can conditionally set using ngStyle. refer the following code.
<div [ngStyle]="{'background-color':isTrue === true ? 'green' : 'red' }"></<div>
Or refer the stackblitz link for another solution.
enter link description here
You can set different class to each element
<ul class="days">
<li *ngFor="let day of currentDays; let i = index" [class]="'day'+(index+1)">
{{day}}
</li>
</ul>
in css set style to each one:
.day1{
...
}
You can use
<li [class.your-class]="expression">
For example:
<li [class.mat-elevation-z10]="i === selectedElement">
Or you can use ngClass with expressions
<li [ngClass]="{'first': true, 'second': true, 'third': false}">
Where first, second and third are your classes and true, true, false are the expressions. In the example above, both first and second class would be applied.
You can use ngClass itself with conditions. You can replace RequiredDay string with variable.
<ul class="days">
<li [ngClass]="{'desiredClass':day === 'RequiredDay'}" *ngFor="let day of currentDays; let i = index" (click)="setStyle()">
{{day}}
</li>
</ul>

How to render a list of static content with Vue named slot?

I have trouble figuring out how to get the following to work:
My parent template
<comp>
link 1
link 2
</comp>
and my component comp template looks like the following:
<ul class="comp">
<li class="comp-item"><slot name="links"></slot></li>
</ul>
currently all my anchors goes to that single li tag (which is expected)
but I would like to be able to produce multiple li for every named slot I inserted like the following:
<ul class="comp">
<li class="comp-item">link 1</li>
<li class="comp-item">link 2</li>
</ul>
Is there any way to achieve what I need without using scoped slot? Because my content is pure HTML so I feel it is unnecessary to put static content inside prop in order to render them.
From what I have seen, most vue UI framework requires you to use another custom component for the list item, which I feel is over killed for the problem. Is there any other way to do this?
This is easily accomplished with a render function.
Vue.component("comp", {
render(h){
let links = this.$slots.links.map(l => h('li', {class: "comp-item"}, [l]))
return h('ul', {class: 'comp'}, links)
}
})
Here is a working example.
console.clear()
Vue.component("comp", {
render(h){
let links = this.$slots.links.map(l => h('li', {class: "comp-item"}, [l]))
return h('ul', {class: 'comp'}, links)
}
})
new Vue({
el: "#app"
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<comp>
link 1
link 2
</comp>
</div>
Or with the help of a small utility component for rendering vNodes you could do it like this with a template.
Vue.component("vnode", {
functional: true,
render(h, context){
return context.props.node
}
})
Vue.component("comp", {
template: `
<ul class="comp">
<li class="comp-item" v-for="link in $slots.links"><vnode :node="link" /></li>
</ul>
`
})
new Vue({
el: "#app"
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<comp>
link 1
link 2
</comp>
</div>
You can make use of scoped slots instead of slots
Your comp component receives a prop links which is an array of links(since static initialized as a custom option). Iterate over the links and pass link as data to the slot just like passing props to a component
Vue.component("comp", {
template: `
<ul class="comp">
<li class="comp-item" v-for="link in links">
<slot v-bind="link"></slot>
</li>
</ul>
`,
props: ["links"]
})
new Vue({
el: "#app",
// custom static option , accessed using vm.$options.links
links: [
{text: "link1"},
{text: "link2"},
{text: "lin3"}
]
})
In the parent where the comp component is used make use of a <template> element with a special attribute slot-scope , indicating that it is a template for a scoped slot.
The value of slot-scope will be used as the name of a temporary variable that holds the props object passed from the child:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<comp :links="$options.links">
<template slot-scope="link">
{{link.text}}
</template>
</comp>
</div>
Here is the working fiddle
If you don't like to put your data in array, and render list with v-for
You can put all of them in the component, no slot:
<ul class="comp">
<li class="comp-item">link 1</li>
<li class="comp-item">link 2</li>
</ul>
or with slot:
<comp>
<ul class="comp" slot="links">
<li class="comp-item">link 1</li>
<li class="comp-item">link 2</li>
</ul>
</comp>

How to access item in <slot> inside v-for (vue.js)

How to send item from v-for to slot? In vue.js.
ListComponent:
<ul>
<li v-for="item in list">
<slot></slot>
</li>
</ul>
Page view:
<list-component :list="list">
<span v-text="item.value"></span>
</list-component>
Code <span v-text="item.value"></span> can't access item (from component's scope). Is it a way to send an item from component to code in tag?
P.S. I know, that as a workaround I can send $index from component to parent view, but it's a little bit hacky
UPD: Example of my current workaround (somebody may find this useful):
Declare index in view's data:
data () {
return {
index: 0,
list: [ ... ]
}
Add to index param to the view's template:
<list-component :list="list" :index="index">
<span v-text="list[index].value"></span>
</list-component>
Declare index in component's props:
props: {
index: {
type: Number
}
}
Add index to v-for's element:
<ul>
<li v-for="item in list" index="$index">
<slot></slot>
</li>
</ul>
the bind expression is compiled in the context who define them,so:
v-text="item.value"
can not be compiled because in Page view there is no "item" defined.
maybe you can try to change your code structure like below:
ListComponent:
//content in component
<span>i am text in component,item value is:{{item.value}}</span>
<slot></slot>
Page view:
<ul>
<li v-for="item in list">
<list-component :item="item"></list-component>
</li>
</ul>

Apply ng-class to parent element if any checkbox is clicked using Angular?

I have a parent list with a dropdown of checkboxes that you can see if you click on the list. What I want to do is give the parent list class "active" if any of the checkboxes are checked. What's happening now is that I have multiple lists so if the checkbox is checked all lists will get that class when I only want the list the checkboxes are in to get the "active" class. How can I refactor this so only the "active" class is given to the parent list, not all lists?
HTML:
<ul ng-repeat="type in filterTypes">
<li ng-repeat="filter in type.filters" ng-class="{active:checked}">{{filter.value | uppercase}}
<ul>
<li ng-repeat="option in filter.options">
<label>
//if any checkbox is checked, the active class should be given to the parentd list at the way top.
<input type="checkbox" ng-model="checked"/>
{{option}}
</label>
</li>
</ul>
</li>
</ul>
Directive:
return {
restrict: "E",
templateUrl: 'scripts/directives/all-filters.html',
link: function(scope, el, attr) {
scope.filterTypes = dummyData.filters;
}
}
Apply the checked property to each option by changing the model to ng-model="option.checked"
Then on the li element change the ng-class directive to call a function to check if any option within the filter is checked
$scope.isAnyChecked = function(filter) {
for (var i = 0; i < filter.options.length; i++) {
if (filter.options[i].checked) {
return true;
}
}
return false;
}
Then apply the active class if it returns true
ng-class="isAnyChecked(filter) ? 'active' : ''"
<input ng-model='checked' ng-change='filter.checked=checked'/>

Categories