Testing for Nested divs using Vue Test Utils - javascript

So I have this shallowMounted vue component:
<div class="card p-relative">
<div class="card-header">
<div class="card-title h4">
a cute title
<!---->
<!---->
</div>
</div>
<!---->
<div class="card-body">
<h3 class="circle" style="background-color: rgb(237, 15, 59);"></h3>
</div>
<div>
<h6 class="card-body">Value: 35</h6>
</div>
</div>
I am doing a shallowMount:
const wrapper = shallowMount(Component, { proposData: { 'shape': 'circle'}})
Later trying to find all the classes, so I can somehow find the class circle. But what I got:
const results = wrapper.classes()
console.log(results) // ['card', 'p-relative']
How to find the h3 or class 'circle' :/
Completely Noob to frontend. Please forgive for using wrong vocabulary.

As mentioned in https://vue-test-utils.vuejs.org/api/selectors.html to access direct descendants.
I did the following:
const shape = wrapper.find('.card-body > h3')
console.log(shape.classes()) //['circle']

Related

In Knockout how do you go about nesting custom components when using an html binding?

I'm a bit new to knockout. I'm trying to get a custom component to dynamically load another custom component. I have a variable called location_board that contains html and that html has a custom component in it. . When I use the data-bind="html: location_board" it put the line for the in the dom but it doesn't run the custom component to fill out that node. Note: If I add the npc-widget directly to the template it works. It just doesn't work when it is added though the html binding. From my research I think this means I need to applyBindings on it? I'm not sure how to go about that in this situation though.
Any help is apricated.
Here is my full code for the custom component.
import {Database} from './database.js'
let database = new Database();
import {ResourceManager} from "./resource-manager.js";
let resourceManager = new ResourceManager();
let locationRegister = {
fog_forest: {
name: "The Ghostly Woodland",
image: "url('img/foggy_forest.jpeg')",
description: `
Place holder
`,
location_board: `
<npc-widget id="john-npc" params="id: 1, tree: 'shopkeep', speed: 50"></npc-widget>
<div>In</div>
`
}
};
ko.components.register('location-widget', {
viewModel: function (params) {
let self = this;
self.function = function () {
console.log("Functions!")
}
for(let k in locationRegister[params.id]) {
console.log(k)
this[k] = locationRegister[params.id][k];
}
console.log(this.name)
//return { controlsDescendantBindings: true };
},
template:
`
<div class="row">
<div class="col-lg-12">
<h2 id="title" class="tm-welcome-text" data-bind="html: name"></h2>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div data-bind="style: { 'background-image': image}" class="location-picture mx-auto d-block">
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="location-description mx-auto d-block" data-bind="html: description"></div>
</div>
</div>
</div>
<hr>
<div class="row">
<div class="col-lg-12">
<div id="location_board" data-bind="html: location_board">
</div>
</div>
</div>
`
});

How to pass an object from ngFor to the component in angular?

I'm new to Angular and I can't really understand what is the problem I'm facing. I'm trying to pass object from an *ngFor to his component.
Here is a simple *ngFor that iterate an Array
<div class="card text-center" *ngFor="let alarm of alarms">
<div class="card-header">
....
</div>
<div class="card-body p-2">
<span class="text-secondary font-weight-bold">
Floor
<span>{{ alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].floor }}</span>
</span>
</div>
</div>
I want to avoid this long interpolation so I want pass the current let alarm to the component and assign three attributes to an object and display it,
customMethod(alarm) {
this.location.floor = alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].floor;
this.location.room = alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].room;
this.location.bed = alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].bed;
}
Here is what I expect:
<div class="card text-center" *ngFor="let alarm of alarms">
<div class="card-header">
....
</div>
<div class="card-body p-2">
<span class="text-secondary font-weight-bold">
Floor
<span>{{ location.floor }}</span>
</span>
</div>
</div>
And show the attribute's object location with string interpolation for each object alarm.
What is the best way to do this?
You want to avoid having any logic in your template (.html) file so I'll advise doing the logic in your component file.
You can prepare the alarms array before it's sent into the template.
#Component(..)
export class SomeComponent {
private _alarms;
#Input()
set alarms(alarms) {
this._alarms = alarms.map(alarm => customMethod(alarm))
}
get alarms() {
return this._alarms
}
}
function customMethod(alarm) {
return {
...alarm, // <<< remove this if you just want locations
locations: {
floor: alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].floor,
room: ....,
bed: ...
}
}
Then in your template
<div class="card text-center" *ngFor="let alarm of alarms">
<div class="card-header">
....
</div>
<div class="card-body p-2">
<span class="text-secondary font-weight-bold">
Floor
<span>{{ alarm.location.floor }}</span>
</span>
</div>
</div>
Create a helper method to get you the value you want to display, and then just call that from the template.
You can do anything to the object to get the value you want to display in here since it's just a funciton:
createMyString(alarm) {
return alarm.sensor.sentinel.monitorings_sentinels[0].monitoring.patient.location[0].floor;
}
Then in your template
{{createMyString(alarm)}}

Binding issue in repeat.for in aurelia

I have a list of cards that i populate, when i click on each card i want to get and display the correct items displayed for that card.
The problem i am facing is that when i return an array its not binding the correct item to the specific card.
This is my HTML
<div repeat.for="Grouping of categoryItems">
<div class="row">
<div class="col s12 m3 l3">
<div class="card blue-grey darken-1">
<div class="card-content" style="padding:10px">
<span class="card-title white-text truncate">${Grouping.name}</span>
<a if.bind="Grouping.hideDetails" class="btn-floating halfway-fab waves-effect waves-light" click.delegate="Activate(list, Grouping)"><i class="material-icons">add</i></a>
</div>
</div>
</div>
</div>
<div repeat.for="categoryGroupingTypes of categoryItemTypes">
<div class="row" if.bind="!Grouping.hideDetails">
<div class="col" style="position:absolute;padding:5%">
<div class="rotate-text-90-negative">
<span class="blue-grey-text"><b>${categoryGroupingTypes.name}</b></span>
</div>
</div>
<div repeat.for="item of categoryItemsTypes.items" class="col s12 m3 l3 ">
<div class="card-content">
<span class="card-title white-text truncate">${items.Name} ${items.Quantity}</span>
</div>
</div>
</div>
</div>
</div>
</div>
my ts
async Activate(list: ListModel[], grouping: any) {
this.categoryItemsTypes = await this.getTypes(list);
let result = this.categoryItem.filter(x => x.name == grouping.name)
if (result) {
grouping.hideDetails = false;
}
}
so this.categoryItemsTypes has the following array
0: {name: "Clothes", items: Array(3)}
1: {name: "Shoes", items: Array(2)}
so when the page loads it loads the cards as follows
then when i click on "Clothes"
i only want it to load the array associated with clothes and if "shoes" is clicked then only load that array as follows
but what is currently happening with my above code is the following
this line is where i bind the items
repeat.for="item of categoryItemsTypes.items"
how can i bind the items to the correct ${Grouping.name} as shown in picture 2?
You are in the right direction, but not complete yet.
Array assignment are not observed by aurelia.
In general, when populating arrays with a new set of elements, this is a good way:
destarray.splice(0, destarray.length, ...sourcearray);
over
destarray = sourcearray;
because the former is observed by aurelia by default and the latter is not.

how to rendering data from api in vue.js

I am new to vue.js I am going to make a news app using a API.
In here I used v-for to iterate some codes. I think there is a problem in v-for. because it gives error. error has been included end of this question.
I used following codes to show search results
<template>
<div class="col-md-12">
<div>
<h2>Results</h2>
<div class="card mb-3" v-for="item in resultList">
<img class="card-img-top" src="" alt="Card image cap" height="100" width="200">
<div class="card-body">
<h5 class="card-title">{{ item.name }}</h5>
<p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
<div class="button">
<button type="button" class="btn btn-primary">Show more</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default{
props: ['resultList']
}
</script>
following codes used to get the api data(search api data)
<template>
<div class="container1">
<div class="form-group row">
<label for="exampleInputPassword1">Search Music</label>
<div class="col-lg-10">
<input type="text" class="form-control" id="exampleInputPassword1" placeholder="Type here"
#input="keypressed">
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default{
data () {
return {
newset: []
}
},
methods: {
keypressed () {
var key = event.target.value
axios.get('http://newsapi.org/v2/everything?q=' + key +
'&sortBy=publishedAt&apiKey=b5ac77726d0a4460bd82b57210b2efb7')
.then(response => {
this.newset = response.data.articles
})
.catch(e => {
this.error.push(e)
})
this.$emit('newDataset', this.newset)
}
}
}
</script>
but it gives an error. error is
https://google.com/#q=vue%2Frequire-v-for-key Elements in iteration expect to have 'v-
bind:key'
directives
src\components\ResultArea.vue:5:5
<div class="card mb-3" v-for="item in resultList">
^
You need to add :key binding:
<div class="card mb-3" v-for="(item, index) in resultList" :key="index">
key value should be unique for every item. If your list items has any id it is good idea to use this id here:
<div class="card mb-3" v-for="item in resultList" :key="item.id">
To give Vue a hint so that it can track each node’s identity, and thus reuse and reorder existing elements, you need to provide a unique key attribute for each item. check the link for better understanding
https://v2.vuejs.org/v2/guide/list.html#Maintaining-State

dynamically add classes to content coming from *ngFor from an array

Im not quite sure something like this is possible but say in my html component I have an ngFor like so..
<div *ngFor="let card of cards">
... stuff in here
</div>
now say I have an array of classNames like so
classNames = [
'red',
'yellow',
'blue',
'green'
]
and inside my *ngFor I have a div like so
<div *ngFor="let card of cards">
<div [class]='...'>
<div class="card">
</div>
</div>
</div>
basically what I want to happen is for every item in the ngFor give loop through the classNames array and dynamically add it to the incoming data so for example
say I have 6 items in cards so each card needs a classname so it loops through classNames and gives it a class so like this..
<div [class]='red'>
<div class="card">
</div>
</div>
<div [class]='yellow'>
<div class="card">
</div>
</div>
<div [class]='blue'>
<div class="card">
</div>
</div>
<div [class]='green'>
<div class="card">
</div>
</div>
<div [class]='red'>
<div class="card">
</div>
</div>
<div [class]='yellow'>
<div class="card">
</div>
</div>
and so on and so forth..
how could i accomplish something like this?
EDIT
component.html
<div class="card" *ngFor="let card of cards; let i = index">
<div [class]="classNames[i%classNames.length]">
....
</div>
</div>
component.ts
export class...
classNames = [
'light-green',
'dark-green',
'aqua',
'blue',
'blue-purple',
'purple',
'purple-pink',
'purple-orange'
];
You can leverage remainder (%) operator to achieve that:
<div *ngFor="let card of cards; let i = index">
<div [class]="classNames[i%classNames.length]">
<div class="card">
{{ card }}
</div>
</div>
</div>
Ng-run Example
Update:
You should define array as follows:
classNames = [
'light-green',
'dark-green',
'aqua',
'blue',
'blue-purple',
'purple',
'purple-pink',
'purple-orange'
];
Note: i use = instead of :
Instead of randomly applying any class to any card or deciding it on view based on some %, the best way, I believe would be read it from the Cards object itself, since it is logical to have all details of a card read from the card itself.
So that view is independent of those extra stuffs.
classNames = ['red','yellow','blue','green'];
cards = [{text: 1, class: this.classNames[0]},{text: 2, class: this.classNames[1]}];
your view should simply do its task (render)
<div *ngFor="let card of cards; let i = index">
<div [class]="card.class">
<div class="card">
{{ card.text}}
</div>
</div>
</div>

Categories