How to retrieve the elements from Shadow DOM and pass property? - web-component

With the help of Lit library we have implemented the component that should render the list with items, where each item is rendered with a separate component:
<div>
<slot name="label"> Here goes the title </slot>
<slot name="list"></slot>
</div>
We pass data to the component like following:
<webc-list ?divided=${true}>
<span slot="label">Title</span>
<ul slot="list">
${items.map(
item =>
html`<webc-list-item
>${item}</webc-list-item
>`,
)}
</ul>
</webc-list>
My question is how can I pass the divided property to the <webc-list-item>.
I tried to access the elements
firstUpdated() {
const dividedProperty = this.divided;
this.renderRoot.querySelector('slot[name=list]')?.assignedElements({ flatten: true })
?.forEach(el => {
if (el && el.tagName && el.tagName.toLowerCase().includes('webc-list-item')) {
el.setAttribute('divided', `${dividedProperty}`);
}
});
But it doesn't work like this, any help would be appreciated!

Related

how to get the name and value of the checked checkbox of child component from parent component in vue js?

Child Component
<template>
<ul>
<li class="dropdown">
<div>
<label class="form-control" ref="checkValue" v-for="(item, index) in list" :key="index">
<input type="checkbox" ref="checkUpdatedBox" :name="item.name" :value="item.name" #click="selectedFilteredArray(item)" />
{{ item.name }}
</label>
</div>
</li>
</ul>
</template>
Here I want the name(item.name) or value(item.name) of the checkbox from the child component. As the input box is rendered dynamically with for loop.
Parent Component
<template>
<ChildComponent ref="checkboxes"/>
</template>
<script>
import SideBar from '../layouts/SideBar.vue'
export default {
methods: {
updateFunction() {
const unCheckBoxes = this.$refs.checkboxes.$refs.checkUpdatedBox
const unCheckBoxes1 = this.$refs.checkboxes.$refs.checkValue
console.log('unCheckBoxes1 ', unCheckBoxes1.innerText)
console.log(unCheckBoxes.checked) // true
}
}
}
</script>
In parent component, I'm trying to access name and value of the checkbox with the help of $refs and yes I'm trying to get name and value of the checkbox from a function. I'm only getting to know that whether the checkbox is checked or not.
But i want to know that checked checkbox value(item.name) or name(item.name).
is there something I'm missing out?
or
Is there any other method to get the name or value?
You can slimily use JavaScript to get value of selected checkbox.
var checkedValue = [];
var inputElements = document.getElementsByClassName('checkbox');
for(var i=0; inputElements[i]; ++i){
if(inputElements[i].checked){
checkedValue.push({value:inputElements[i].value,name:inputElements[i].name});
}
}
console.log(checkedValue);

Highlight the css cards upon search in angular

I have array of items which are rendered on UI as angular material cards. I have a search box where user input for items. once the search is implemented I get the searchItems as another array. Now I want to highlight (changing the background color of the card or a rectangular animation) items array angular material cards which are matched with searched items. I was stuck at implementing this css part although I am able to render and match the items with searchdItems
<div *ngIf="searchedItems">
<div class="alert alert-danger alert-dismissible" *ngIf="searchedItems.length === 0">
&times
<strong>{{data.value}}</strong> not found
</div>
<div *ngIf="searchedItems.length > 0" class='searchitem'>
{{data.value}} found in
<div *ngFor="let item of searchedItems; let i = index">
{{item}} {{i}}
</div>
</div>
</div>
<mat-grid-list cols="3" rowHeight="100px">
<div *ngFor="let item of items; let x = index">
<mat-grid-tile [ngClass]="item.name == item ? 'searchexample-card': 'example-card'" routerLink="/inventory/items/{{item.name}}">
<mat-card>
<mat-card-header>
<b>Item{{item.name}}</b>
</mat-card-header>
</mat-card>
</mat-grid-tile>
</div>
</mat-grid-list>
If you are unable to change the items array I have modified the answer for the pipe which will not impact your original array
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'highlight', pure: false
})
export class HighlightPipe implements PipeTransform {
transform(items: any, filtered?: any[]): any {
let newArray = [];
if(Array.isArray(items) && Array.isArray(filtered)) {
for(let item of items){
newArray.push({label: item, highlight: filtered.indexOf(item)>-1})
}
} else {
newArray = items.map(item => ({label: item}));
}
console.log(newArray)
return newArray;
}
}
But your html template will be modified to accommodate the highlight
<div *ngFor="let item of items | highlight: searchedItems" [ngClass]="{card: true, highlight: item.highlight}">
{{item.label}}
</div>
Here I am passing the array that you have after you search searchedItems to my highlight Pipe
Hope this answers your question
Updated Stackblitz: https://stackblitz.com/edit/angular-oyhva7
The problem is with the condition that you have implemented for activating [ngClass]. You are comparing an object with object property, this comparison for item with item.name will always return false.
consider you have the searched result in searchedItems[] array. Now you want to highlight those items in the loop of whole items. then your code should be something like this
<div *ngFor="let item of items; let x = index">
<mat-grid-tile [ngClass]="item in searchedItems ? 'searchexample-card': 'example-card'">
<mat-card>
<mat-card-header>
<b>Item{{item.name}}</b>
</mat-card-header>
</mat-card>
</mat-grid-tile>
</div>
Considering your items array and searchedItems[] is of same type.
You can do it using a pipe from Angular
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'highlight',
pure: false
})
export class HighlightPipe implements PipeTransform {
transform(items: any, search: string, clip: boolean): any {
const regex = new RegExp(search, 'ig');
if(Array.isArray(items) && search) {
for(let item of items) {
item.highlight = regex.test(item.label);
}
}
return clip ? items.filter(item => item.highlight) : items;
}
}
I have passed in the search term in the pipe and the full array always returning from the pipe, but using a regular expression or maybe your custom logic of search add another attribute to the list item highlight boolean which is true if your logic says it matches the item, else false
I have modified the items array from string[] to {label:string, highlight?:boolean}[] to accommodate the pipe change so instead we are using the array as
items: {label:string, highlight?:boolean}[] = [
{label: 'INDIA'},
{label: 'USA'},
{label: 'RUSSIA'},
{label: 'UK'},
{label: 'ITALY'},
];
Now to all put it into the template
<div
*ngFor="let item of items | highlight: search"
[ngClass]="{highlight: item.highlight, card: true}"
>
{{item.label}}
</div>
Here when you search, if it matches with any of the item from items array will have a highlight:true attribute as true and also adds a class called 'highlight` to your existing div.card so in css defining the highlight card as
.card.highlight{
background-color: yellow;
}
Notice that we are sending the search term to the pipe that we created as an argument, so we have to define the variable as a class level variable which is set when we click search in your method devicesearch which you are already calling.
search: string;
devicesearch(input) {
this.search = input;
}
Edit 2:
If you wanted the clipped array you can use the Pipe in your class to get the clipped array
search: string;
searchedItems: any[];
highlightPipe = new HighlightPipe();
devicesearch(input) {
this.search = input;
this.searchedItems = this.highlightPipe.transform(this.items, input, true);
// only names --> const names = this.searchedItems.map(item => item.label);
}
Updated StackBlitz for your reference: https://stackblitz.com/edit/angular-usswkn

Gutenberg setAttributes does not update my edit area

How can i make my HTML Elements in Gutenberg binded to an Array/Object?
Hi,
i am programming an Gutenberg Block now and just wanted to bind an Object to my Block but it does not update.
Currently i have an list of 's and wanted to be added automatically if i push the "Click me!" Button.
What it does is... If i push on that button, it pushes the new Element into the Array but the Elements are not added. If i click away (if the block loses focus), the elements are added.
What did i do wrong?
edit: props => {
const { setAttributes, attributes } = props;
let slides = props.attributes.slides;
const addSlide = function(event){
slides.push({ title : 'new' });
setAttributes({ slides: slides });
}
return [
<InspectorControls key="inspector">
<PanelBody
title={'Slides'}
initialOpen={true}
>
{slides.map((slide, i) =>
<li key={i}>
{slide.title}
</li>
)}
<Button isPrimary onClick={addSlide}>
Click me!
</Button>
</PanelBody>
</InspectorControls>,
<div className={ props.className } key='richtext'>
{slides.map((slide, i) =>
<li key={i}>
{slide.title}
</li>
)}
<Button isPrimary onClick={addSlide}>
Click me!
</Button>
</div>
];
}
I'm expecting the list elements to add dynamically while foxused.

Vue 2.0 Laravel 5.3 array and object passsing via forEach

I have the following child methods
methods:{
selectedPC(selectedProductChoice){
this.$parent.$children.forEach(choice=>{
choice.isActive = (choice.id == selectedProductChoice.id)
})
}
}
and my child template is the following
<template>
<transition name="fade">
<li
class="product-choice"
:class="{'selected': productChoice.isActive}"
#click.prevent="selectedPC(productChoice)"
>
......
......
......
</li>
</transition>
</template>
and here is where the child product-choices is called by the the parent template
<ul class="product-choices" v-show="thumbnailHover">
<product-choices v-for="(productChoice, index) in productChoices" :key="productChoice.id" :product="product" :product-choice="productChoice" :index="index"></product-choices>
</ul>
Not sure why but the choice in the forEach in child template is an object which does not allow me to read choice.id (undefined as I tried to alert it). Is it array object problem? I kind of follow the tabs tutorial from Vue 2 Laracast for you reference.
You have to try child.$data to access the data associated with the child, like following:
methods:{
selectedPC(selectedProductChoice){
this.$parent.$children.forEach(choice=>{
choice.$data.isActive = (choice.$data.id == selectedProductChoice.id)
})
}
}

How to access array elements inside vue.js conditional css class

I'm getting starting with Vue.js and I have a simple page set up to experiment with conditional css.
<div id="app">
<div class="demo" #click="handleClick(0)" :class="{ 'red': attachRed[0] }">
</div>
<div class="demo" #click="handleClick(1)" :class="{ 'red': attachRed[1] }">
</div>
<div class="demo" #click="handleClick(2)" :class="{ 'red': attachRed[2] }">
</div>
</div>
and then my js
new Vue({
el: "#app",
data: {
attachRed: [false, false, false]
},
methods: {
handleClick: function(index) {
this.attachRed[index] = !this.attachRed[index];
console.log(this.attachRed)
}
}
});
Each div is a grey block. When attaching the "red" class, the block turns red. attachRed array is updating every time a demo div is clicked. But the class is never added. If I start the attachRed property off as being true, then the red class is attached initially, but this isn't toggled when clicked. This works if these values aren't stored in an array though.
Is it possible to make the view bindings watch for these changes or to manually trigger one? Or is there some sort of gotcha when it comes to array properties?
It is a gotcha. This page goes into it a bit: https://vuejs.org/2016/02/06/common-gotchas/
In short, you want to do
var val = this.attachedRed[index]
this.attachedRed.$set(index, !val);

Resources