Vue change style in for Conditionally - vue.js

I have a v-for and I need to change a style according to the return of a given data.
<div id="beerApp">
<ul>
<li v-for="cervejaria in cervejarias">
<span class="CHANGE Conditionally IF cervejaria.name == 'foo' ">{{cervejaria.name}}</span>
</li>
</ul>
</div>
In the angular it is like following:
ng-class="cervejaria.name == 'Foo' ? 'task-cat blue lighten-5 black-text' : 'task-cat green'"

You can use dynamic class binding via v-bind to dynamically change the class as following:
<li v-for="cervejaria in cervejarias">
<span v-bind:class="{'myClass' : cervejaria.name == 'foo'}"> {{cervejaria.name}}</span>
</li>
So in above code, myClass will be applied only if condition cervejaria.name == 'foo' is true.

Related

Is there a function in Laravel Livewire that allows the value property of a html element to be passed into a function?

Is there a function in Laravel Livewire that allows the value property of a html element (be it a radio button, checkbox, dropdown list or textbox) to be passed into a function?
For example: I have on a page a list. This list consists of different cooked dishes. I select a dish from the list by clicking on it and the value passed. Can this value be passed into a function?
LiveWire Controller
<?php
namespace App\Http\Livewire;
use Livewire\Component;
class Dishes extends Component
{
public function showRecipe($value)
{
//query database or some conditional logic
}
public function render()
{
return view('livewire.dishes')
}
}
LiveWire Component
<div>
<ul>
<li value="pizza" wire:click="showRecipe(this.value)">Pizza</li>
<li value="cherry_pie" wire:click="showRecipe(this.value)">Cherry Pie</li>
<li value="beef_stronganoff" wire:click="showRecipe(this.value)">Beef Stroganoff</li>
<li value="caesar_salad" wire:click="showRecipe(this.value)">Caesar Salad</li>
<li value="lobster_newburg" wire:click="showRecipe(this.value)">Lobster Newburg</li>
</ul>
</div>
value is not a valid attribute on an <li> tag. However, you can put an anchor-tag with a "prevent default" action it, or just keep the wire:click on the li and pass the data directly to the method.
<div>
<ul>
<li wire:click="showRecipe('pizza')">Pizza</li>
<li wire:click="showRecipe('cherry_pie')">Cherry Pie</li>
<li wire:click="showRecipe('beef_stronganoff')">Beef Stroganoff</li>
<li wire:click="showRecipe('caesar_salad')">Caesar Salad</li>
<li wire:click="showRecipe('lobster_newburg')">Lobster Newburg</li>
</ul>
</div>
If you generate this in a loop with PHP/blade, you should use wire:key on it. The key should be something unique, so Livewire can keep track of each individual record.
<div>
<ul>
#foreach([
'pizza' => 'Pizza',
'cherry_pie' => 'Cherry Pie',
'beef_stronganoff' => 'Beef Stroganoff',
'caesar_salad' => 'Caesar Salad',
'lobster_newburg' => 'Lobster Newburg',
] as $value=>$name)
<li wire:key="dish-{{ $loop->index }}" wire:click="showRecipe('{{ $value }}')">{{ $name }}</li>
#endforeach
</ul>
</div>

Vue check in nested v-for if a record doesn't exist

I am trying to build a table where rows are items (first v-for), columns are locations (second v-for), cells are item_locations (third -v-for).
If for a certain location the item is present (hence an item_location object) I want to print yes, else I want to print No.
<div v-for="item in items" :key="item.id>
{{item.name}}
<div v-for="location in locations" :key="location.id">
<div v-for="item_location in location.item_locations" :key="item_location.id">
</div>
</div>
</div>
By adding this in the third loop:
<p v-if="item_location.item_id == item.id">Yes</p>
I it correctly prints yes for combination of item/location for which there is an item_location.
What I am unable to do is to print No only for the combinations of item/location for which an item_location object does not exist. To further clarify, item_locations is a joining table.
A little confused on what your asking but Im going to suggest this
Your nested v-for must use the property declared from its parent like so
<div class="table-cell" v-for="location in locations" :key="location.id">
<div v-for="item_location in location.item_locations" :key="item_location.id">
<div v-if="item_location.location_id == location.id ">Yes</div>
<div v-else>No</div>
</div>
</div>
so the nested v-for would be location.item_locations and if your only checking for one condition you can just do a v-else.
I solved this way:
<div v-for="item in items" :key="item.id>
{{item.name}}
<div v-for="location in locations" :key="location.id">
<div>{{filterLocation(item, location)}}</div>
</div>
</div>
filterLocation: function(item, location) {
let value = item.item_locations.filter(item_location => {
return item_location.location_id == location.id;
});
var that = this;
that.item_location_exists = value.length;
},
And in template I can do a conditional as item_location_exists equals to 0 or 1.

How can I find the exact value using xpath in selenium webdriver for text that contains ?

I'm having an issue selecting the exact text 'Section' from the code using xpath.
** To be clear I require the exact text selection to be made from the innerText or innerHTML of the element if that is possible, not the id. **
I'm able to use the contains text function, but that results in other partial matches that contain 'Section' being returned/highlighted as well:
//div[#aria-hidden='false']//ul/li[contains(text(),'Section')]
I've tried using the following methods, but I don't know if I've got the syntax correct, as nothing is returned/highlighted:
//div[#aria-hidden='false']//ul/li[text()='Section')]
//div[#aria-hidden='false']//ul/li[.='Section']
//div[#aria-hidden='false']//ul/li[normalize-space(.)='Section']
This is what is shown when inspecting the Section node:
<li id="GOS--/40" class="nodecollapsed item parent-node xh-highlight" style="" xpath="1">
Section <span class="child-count"></span>
</li>
This is what is shown in the element properties:
id: "GOS--/40"
innerHTML: "↵ Section <span class="child-count"></span>↵ "
innerText: " Section "
Here is the xml which shows the other partial matches that are returned:
<div class="selection-list-dialog modal-dialog Dialog">
<div class="modal-content">
<div class="modal-header SectionHeader">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<span class="modal-title" data-lang="StandardItems">Standard Items</span>
</div>
<div class="modal-body selection-list-container" style="margin-top: 30px" id="base">
<div>
<span data-lang="SelectItemInstructions">Select the items you are interested in from the list.</span>
</div>
<br/>
<div class="pull-left selection-tree-container">
<h4 class="selection-list-title">
<span data-lang="Available">Available</span>
</h4>
<ul class="selection-list selection-tree-list">
<li id="CS--/14" class="nodecollapsed item parent-node">
Country Section <span class="child-count"></span>
</li>
<li id="Sec1--/23" class="nodecollapsed item parent-node">
Section 1 <span class="child-count"></span>
</li>
<li id="Sec2--/24" class="nodecollapsed item parent-node">
Section 2 <span class="child-count"></span>
</li>
<li id="GOS--/40" class="nodecollapsed item parent-node">
Section <span class="child-count"></span>
</li>
<li id="RS--/43" class="nodecollapsed item parent-node">
Regional Section <span class="child-count"></span>
</li>
This was a tough one. The problem is that you have a number of similar options all containing "Section" in some flavor and it's hard to distinguish them apart. What adds to this is that each one contains a non-breaking space which means that normalize-space() won't work (directly) either.
But... I found that the below XPath will work.
//li[normalize-space()='Section\u00a0']
normalize-space() removes whitespace (but not &nbsp) so you have to add it in there with \u00a0. I've tested this locally and it's working.
Try following xpath see if it helps.
//li[starts-with(#id,'GOS')][#class='nodecollapsed item parent-node xh-highlight']
OR
//li[#class='nodecollapsed item parent-node xh-highlight'][#xpath='1']
you can try the below XPath to find a section node
Try if it helps
//li[#id='GOS--/40'][contains(text(),'Section')]
Let me throw my hat into the ring....
//li[(normalize-space(text()) = 'Section')]
Here is the method that will fetch the text from the parent only. (exclude the text in the child(ren))
In Python:
def get_pure_element_text(element):
return driver.execute_script(
"""
var parent = arguments[0];
var child = parent.firstChild;
var textValue = "";
while(child) {
if (child.nodeType === Node.TEXT_NODE)
textValue += child.textContent;
child = child.nextSibling;
}
return textValue;""",
element).strip()
This method will iterate all the firstChild (direct children) and extract all text from all the text nodes.
In this context If you want to retrieve the text of li which have the id GOS--/40 then use the method as below.
element = driver.find_element_by_xpath("//li[#id='GOS--/40']")
print(get_pure_element_text(element))
Sharing this method, at least might help the others (if not the OP in this context).
C# implementation:(not tested)
string get_pure_text(IWebDriver driver, IWebElement element){
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
return (string)js.ExecuteScript(""""
var parent = arguments[0];
var child = parent.firstChild;
var textValue = "";
while(child) {
if (child.nodeType === Node.TEXT_NODE)
textValue += child.textContent;
child = child.nextSibling;
}
return textValue;""",
element");
Usage:
string output = get_pure_text(driver,element)

Using vue, determine which radio input is selected by accessing $refs

I populate some radio buttons from an array of options. I would like to determine which radio button was select using $refs, however when I log out the $refs it gives me all of the radio buttons.
Is it possible to just grab the select radio button using $refs? Can you some how combine event.target with the $refs or something? Furthermore how to I access parts of that ref like the class of the element that was selected. I am trying to use just vue to do this but has proven difficult.
thanks for any help you can provide.
<li
class="mc-option"
v-for="(option, i) in options"
:key="i">
<input
ref="mcOption"
type="radio"
name="option"
:id="'option-' + i"
class=""
#click="radioSelected($event)">
</li>
methods: {
radioSelected: function () {
let mcOption = this.$refs.mcOption
console.log(mcOption)
},)
}
X is your ID:
<ul>
<li v-for="x in 5">
<label :for="`radio${x}`">radio{{x}}</label>
<input type="radio" name="radio" :id="`radio${x}`" #change="getRef(`radio${x}`)" :ref="`radio${x}`">
</li>
</ul>
methods: {
getRef (ref) {
console.log(this.$refs[ref])
}}
This is happening since all the generated options are having the same ref ids. You could come over this with the following code.
TEMPLATE
<li class="mc-option" v-for="(option, i) in options" :key="i">
<input :ref="['mcOption',i].join('-')" type="radio" name="option" :id="'option-' + i" class="" #click="radioSelected(i)"> {{i+1}}
</li>
JS
methods: {
radioSelected: function (i) {
let mcOption = this.$refs[['mcOption', i].join('-')]
console.log(mcOption)
}
}
Points to note are:
:ref
a variable ref id by using ['mcOption', i].join('-'). This actually can be anything you want (but should change for every v-for iteration).
Please let me know if it does NOT work for you.

How can I switch the `selected` style easily in Vue?

How can I switch the selected style easily?
In the template I have a nav:
<ul class="nav">
<li class="nav-item selected" #click="clickLi(0)"><router-link to="/">首页</router-link></li>
<li class="nav-item" #click="clickLi(1)"><router-link to="/data-center">数据中心</router-link></li>
</ul>
in the methods:
clickLi(page_num){
// there I have to clear all the li `selected` style, then add the style to the page_num.
}
in Vue whether there is a better way to realize this effect?
Take a look at Cass and Style Binding Docs
pseudo example below, also added some shorcuts to vue-router to avoid the router-link component, you just can bind the :to to the <li>
<li
v-for="(item, $index) in routes"
#click="selectedIndex = $index"
:class="{'item-selected': $index == selectedIndex}"
:to="item.path">{{ item.name }}</li>
// on component
data() {
return {
selectedIndex: null,
routes: [{path:'/', name: 'home'},{path:'/data-center', name:'data center'}]
}
}
in the data you return a selected_num param:
data() {
return {
selected_num: 0
}
}
in your template:
<ul class="nav">
<li class="nav-item" :class="selected_num===0 ? 'selected' : ''" #click="selected_num=0"><router-link to="/">首页</router-link></li>
<li class="nav-item" :class="selected_num===1 ? 'selected' : ''" #click="selected_num=1"><router-link to="/data-center">数据中心</router-link></li>
</ul>
you even do not need the method.