Vuetify Table - rendering column value based on a condition - javascript

I have a vuetify table and one of the columns is url. I need to add logic to either display URL or URL Group name. I can tell that based on the property of my rules array. If my rules[i].urlGroup != '' then I know
I have tried to add
<template v-slot:item.url="{ index, item }">
{{ displayURLInfo(index) }}
</template>
displayURLInfo(index) {
if (this.rules[index].urlGroup != '') {
// console.log('this.rules[index].urlGroup', this.rules[index].urlGroup) // here printed perfectly on console.
return this.rules[index].urlGroup
} else {
return this.url
}
}
I was inside the first if condition, it consoles log perfectly, but it didn't render to the UI.
My rules array structure look like this. It's only has 5 properties
What did I do wrong?

You have to do below correction in the displayURLInfo() method :
Use urlGroup instead of userGroup.
Instead of return this.url it should be return this.rules[index].url
Working Demo :
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
headers: [
{ text: "Priority", value: 'priority' },
{ text: "Name", value: 'name' },
{ text: "URL", value: 'url' },
],
rules: [{
priority: 1,
name: "Alpha",
url: 'https://example.com',
urlGroup: ''
}, {
priority: 2,
name: "Beta",
url: 'https://example.com',
urlGroup: 'userGroup2'
}],
}
},
methods: {
displayURLInfo(index) {
if (this.rules[index].urlGroup != '') {
return this.rules[index].urlGroup
} else {
return this.rules[index].url
}
}
}
})
<script src="https://unpkg.com/vue#2.x/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#2.6.4/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify#2.6.4/dist/vuetify.min.css"/>
<div id="app">
<v-app id="inspire">
<v-data-table
:headers="headers"
:items="rules"
>
<template v-slot:item.url="{ index, item }">
{{ displayURLInfo(index) }}
</template>
</v-data-table>
</v-app>
</div>

Related

how to combine two table values to one array in vuetify

I have a vuetify table with multiple values consisting of, Date,start and endtime and votername. What I am trying know is to push on button click two selected rows into one new array object. I can push already the selected rows to one array but each of them being seperate object inside my array but this is not what I want.
this is what I am getting if I push the whole array:
{
"id":null,
"date":"2021-06-18",
"startTime":"23:00",
"endTime":"23:30",
"voterUniqueName":"Hasan",
"meetingName":"hallo"
},
{
"id":null,
"date":"2021-06-18",
"startTime":"23:00",
"endTime":"23:30",
"voterUniqueName":"Turan",
"meetingName":"hallo"
}
but what I want to get is the following:
{
"voterUniqueName": "Hasan",
"voterUniqueName2": "Turan"
},
I want to simplify the two values like this two one array object.
but when I try to push the names of the array I am getting an undefined. Could someone look at my code and tell me where my mistake is?
HTML:
<v-data-table
v-model="selected"
:headers="headers"
:items="filterByDate"
item-key="voterUniqueName"
show-select
class="elevation-1"
>
<template v-slot:top>
<v-col cols="3">
<v-select
:items="availableTimes"
item-text="date"
#select="filterByDate"
v-model="selectedDate"
></v-select>
</v-col>
<v-col cols="12">
<v-chip-group
v-model="selection"
active-class="deep-purple--text text--accent-4">
<v-chip
v-for="(time, i) in dateTimeArray"
:key="time"
:value="time"
#click="getTimesFiltered(time)">
{{ time.startTime +" : "+ time.endTime }}
</v-chip>
</v-chip-group>
</v-col>
</template>
</v-data-table>
script:
<script>
import axios from "axios";
export default {
name: "MeetingAdminComponent",
data : ()=>({
singleSelect: false,
selected: [],
meetingArray: [],
headers: [
{
text: 'Date',
align: 'center',
value: 'date',
},
{ text: 'Voter', value: 'voterUniqueName' },
{ text: 'Starttime', value: 'startTime' },
{ text: 'Endtime', value: 'endTime' },
],
availableTimes: [
],
}),
methods:{
pushSelected(){
this.meetingArray.push({
name1: this.selected.name,
name2: this.selected.name
})
console.log(this.meetingArray)
}
}
};
</script>
If all you wanna achieve is something like this:
{
"voterUniqueName": "Hasan",
"voterUniqueName2": "Turan"
}
Then simply do something like this:
// In your case this will be the selected items: this.selected
const voters = [
{
"id":null,
"date":"2021-06-18",
"startTime":"23:00",
"endTime":"23:30",
"voterUniqueName":"Hasan",
"meetingName":"hallo"
},
{
"id":null,
"date":"2021-06-18",
"startTime":"23:00",
"endTime":"23:30",
"voterUniqueName":"Turan",
"meetingName":"hallo"
}
]
// Create an empty object to join the items
const joinedVoters = {};
voters.forEach((voter, index) => {
// Gets the voter position plus one for the key
const item = index + 1;
// This will insert the "voterUniqueName in the position 0 of the array as the key "name1"
joinedVoters[`name${item}`] = voter.voterUniqueName;
})
console.log(joinedVoters)
For your specific case, your method should end up looking this:
methods:{
pushSelected(){
const newMeeting = {};
this.selected.forEach((voter, i) => {
const key = `name${i + 1}`;
newMeeting[key] = voter.voterUniqueName;
})
this.meetingArray.push(newMeeting);
console.log(this.meetingArray)
}
}
Just a question I noticed that my structure is completely wrong what I asked in my question. Should I post a new question and mark this one as closed or should I just update my question?

Using an if condition inside a V-For Loop in Vue JS

I am having a problem passing an if condition inside a v-for loop in VueJS. I want to see if a value in the text field is greater than 30 to give an alert but I can't figure out how i can call my function inside the loop. Here is my code: I have tried using v-if but still not lucky
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js">
</script>
<tbody>
<tr> v-for="item in marksData">
<td>{{item.studentName}}</td>
<td>{{item.studentRegNo}}</td>
<td><input v-model.number="item.cat1Marks" required="required" /> *...V-if
to check the condition here.... or call any function to check*</td>
<td><button v-on:click.prevent="saveMarks(item)"
type="submit">Save</button></td>
</tr>
</tbody>
var subjectStudentsVM = new Vue({
el: "#subjectStudentsSection",
data: function() {
return {
id: '',
studentRegNo: '',
studentName: '',
marksData: Array(),
}
},
created: function() {
this.getAllSubjects();
},
methods: {
getAllSubjectStudents: function(subject) {
var self = this;
console.log(this.subject.subjectCode)
axios.get("/Marks/students/" +
this.subject.subjectCode).then(function(response) {
this.marksData = response.data;
}.bind(this)).catch(function(error) {
console.log('Error while fetching student data: ' + error)
})
},
computed:{
CheckData(item) {
if (item.cat1Marks > 30 && item.cat1Marks > 0) {
alert("Marks should be less than 30");
}
console.log(mark);
return mark;
}
}
If I understand your question. I think you should check the input first. Then return the alert() if it's necessary.
inside methods
giveAlert(){
alert("Marks should be less than 30");
}
inside computed:
checkInput(val){
if (val > 30 && val > 0) {
this.giveAlert()
} else {//do nothing}
}
Also mentioned in the comments. You should correct the typo of v-for.
the html will not cause a alert it's self so you have to run the checkdata in the created function.
created:function(){
this.getAllSubjects();
for(var i=0;i<this.marksData.length;i++){
var item=this.marksData[i];
if(item.cat1marks>30){
alert("marks should be less than 30");
}
}
}
Computed variable are defined as functions cause they react on changes in the reactive varables of the vue component. But they are not designed to expect any variable passing them directly.
Use subcomponent created hook like this:
<div id="app">
<p v-for="student in marksData">
<mystudent :student="student" />
</p>
</div>
<script>
var app = new Vue({
el: "#app",
data: function() {
return {
marksData: [{
studentName: 'Alan',
studentRegNo: 1,
cat1Marks: 21
},{
studentName: 'Jessica',
studentRegNo:2,
cat1Marks: 31
},{
studentName: 'Joe',
studentRegNo: 3,
cat1Marks: 4
}],
}
},
components: {
Mystudent: {
props: ['student'],
created() {
if (this.student.cat1Marks > 30) alert(`Student ${ this.student.studentName } reached ${ this.student.cat1Marks } mark`)
},
render (h) {
return h('span', `Name: ${ this.student.studentName } RegNo: ${ this.student.studentRegNo } Marcs: ${ this.student.cat1Marks }`)
}
}
}
});
</script>
UPDATED
After the comment i realized that i didn't understood the question
So here is updated code example, where the score check is in method section not in computed and the trigger is the #change event. Notice the #change triggers first when the focus is taken out of the input field.
<div id="app">
<p v-for="(student, i) in marksData">
Student: {{ student.studentName }} Mark: <input v-model="student.cat1Marks" type="text" #change="checkStudent(student)">
</p>
</div>
<script>
var app = new Vue({
el: "#app",
data: function() {
return {
test: 1,
marksData: [{
studentName: 'Alan',
studentRegNo: 1,
cat1Marks: 21
},{
studentName: 'Jessica',
studentRegNo:2,
cat1Marks: 31
},{
studentName: 'Joe',
studentRegNo: 3,
cat1Marks: 4
}],
}
},
methods: {
checkStudent (student) {
if (student.cat1Marks > 30) alert(`Student ${student.studentName } reached ${ student.cat1Marks } mark`)
}
}
});
</script>
For anyone having a similar problem I added this function
up(item){
if (item.cat1Marks > 30) {
item.cat1Marks=0;
alert("Marks cannot be greater than 30")
}else{}
},
//and called this function in my input
<td> <input type="text" name="cat1Marks"
v-model.number="item.cat1Marks" v on:input="up(item)"
required="required" /></td>

Vue.js : How to iterate with v-for into a dynamic array

I want to display multiples html tables of tools (1 table = 1 tool's categorie / 1 tr = 1 tool).
data() {
return {
cats: '',
tools: [],
};
},
methods: {
getToolCats() {
var rez = getToolCats();
rez.then(data => this.receiveCats(data) )
},
receiveCats(_cats){
this.cats = _cats;
_cats.forEach(cat => {
getToolsByCat(cat.href).then(data => this.tools[cat.href] = data);
});
console.log(this.tools);
},
},
mounted() {
this.getToolCats();
},
cats (ie categories) is an array populated with an API call. Then for each cat, an API Call give me a tool list of that cat, that I place into the tools array (this.tools[cat.href] = data).
Here is the display code :
<div v-for="cat in cats" :key="cat.href" class="tbox col-xs-12 col-sm-6">
....
<table class="table table-hover">
<tr v-for="tool in tools[cat.href]" :key="tool.href">
<td>...</td>
</tr>
</table>
....
</div>
If i'm using a single var to store lthe tool list, all is OK. But while I don't know how many cats I'm going to have, I can't create a car for each category.
I think the problem could be there :
Using an array in v-for with a key not defined at mounted state :
v-for="tool in tools[cat.href]
I'll appreciate any help !
Vue can't detect dynamic property addition in this.tools[cat.href] = data, but it would detect the change with this.$set or Vue.set in this.$set(this.tools, cat.href, data):
new Vue({
el: '#app',
data() {
return {
cats: [],
tools: {}, // <-- make this an object (not an array)
};
},
mounted() {
this.getToolCats();
},
methods: {
getToolCats() {
// setTimeout to simulate delayed API calls...
setTimeout(() => {
this.cats = [
{ href: 'https://google.com' },
{ href: 'https://microsoft.com' },
{ href: 'https://apple.com' },
{ href: 'https://amazon.com' },
];
this.cats.forEach((cat, i) => {
setTimeout(() => {
const data = { href: cat.href };
this.$set(this.tools, cat.href, data); // <-- use this.$set for dynamic property addition
}, i * 1000);
})
}, 1000);
}
}
})
<script src="https://unpkg.com/vue#2.5.17"></script>
<div id="app">
<div v-if="!cats || cats.length == 0">Loading...</div>
<div v-for="cat in cats" :key="cat.href" v-else>
<table>
<tr v-for="tool in tools[cat.href]" :key="tool.href">
<td>cat.href: {{cat.href}}</td>
</tr>
</table>
</div>
<pre>tools: {{tools}}</pre>
</div>

vue.js computed property not triggered

Vue JS computed property is not triggered With this markup
<!-- language: lang-html -->
<p>£{{plant_price}}</p>
<div v-if="selected.plant.variations.length > 0 ">
<select v-model="selected.plant.selected_variation" class="form-control">
<!-- inline object literal -->
<option v-for="(variation, i) in selected.plant.variations" :selected="variation.id == selected.plant.selected_variation ? 'selected' : ''":value="variation.id">
{{variation.name}}
</option>
</select>
</div>
<!-- language: lang-js -->
var app = new Vue({
el: '#vueApp',
data: {
selected: {
type: {a: '' , b: ''},
vehicle: '',
plant: {
}
},
computed: {
plant_price: function() {
if (this.selected.plant.variations.length > 0 ) {
var variant = _.find(this.selected.plant.variations, {id: this.selected.plant.selected_variation });
return variant.price;
} else {
return this.selected.plant.price;
}
}
...
selected.plant is populated by clicking on a plant - triggering the updateSelected method.
<div class="col-sm-4" v-for="(plant, i) in step2.plants">
<div v-on:click="updateSelected(plant)" ....
methods: {
updateSelected: function(plant) {
this.selected.plant = plant; // selected plant
if (this.selected.plant.variations.length > 0 ) {
this.selected.plant.selected_variation = this.selected.plant.variations[0].id; // set the selected ID to the 1st variation
I have checked through the debugger, and can see that all the correct properties are available.
selected:Object
type:Object
vehicle: "Truck"
plant:Object
id:26
price:"52"
regular_price:"100"
selected_variation:421
variations:Array[2]
0:Object
id:420
name:"small"
price:52000
regular_price:52000
1:Object
etc...
I have a computed property, which should update the plant_price based on the value of selected.plant.selected_variation.
I grab selected.plant.selected_variation and search through the variations to retrieve the price. If no variation exists, then the plant price is given.
I have a method on each product to update the selected plant. Clicking the product populates the selected.plant and triggers the computed plant_price to update the price (as the value of selected.plant.selected_variation has changed).
However, the computed plant_price is not triggered by the select. Selecting a new variant does what its supposed to, it updates selected.plant.selected_variation. Yet my plant_price doesn't seem to be triggered by it.
So I refactored my code by un-nesting selected.plant.selected_variation. I now hang it off the data object as
data = {
selected_variation: ''
}
and alter my computer property to reference the data as this.selected_variation. My computed property now works??? This makes no sense to me?
selected.plant.selected_variation isn't reactive and VM doesn't see any changes you make to it, because you set it after the VM is already created.
You can make it reactive with Vue.set()
When your AJAX is finished, call
Vue.set(selected, 'plant', {Plant Object})
There're two ways you can do it, what you are dealing with is a nested object, so if you want to notify the changes of selected to the others you have to use
this.$set(this.selected, 'plant', 'AJAX_RESULT')
In the snippet I used a setTimeout in the created method to simulate the Ajax call.
Another way you can do it is instead of making plant_price as a computed property, you can watch the changes of the nested properties
of selected in the watcher, and then update plant_price in the handler, you can check out plant_price_from_watch in the snippet.
Vue.component('v-select', VueSelect.VueSelect);
const app = new Vue({
el: '#app',
data: {
plant_price_from_watch: 'not available',
selected: {
type: {a: '' , b: ''},
vehicle: "Truck"
}
},
computed: {
plant_price() {
return this.setPlantPrice();
}
},
watch: {
selected: {
handler() {
console.log('changed');
this.plant_price_from_watch = this.setPlantPrice();
},
deep: true
}
},
created() {
setTimeout(() => {
this.$set(this.selected, 'plant', {
id: 26,
price: '52',
regular_price: '100',
selected_variation: 421,
variations: [
{
id: 420,
name: "small",
price: 52000,
regular_price: 52000
},
{
id: 421,
name: "smallvvsvsfv",
price: 22000,
regular_price: 22000
}
]
})
}, 3000);
},
methods: {
setPlantPrice() {
if (!this.selected.plant) {
return 'not available'
}
if (this.selected.plant.variations.length > 0 ) {
const variant = _.find(this.selected.plant.variations, {id: this.selected.plant.selected_variation });
return variant.price;
} else {
return this.selected.plant.price;
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
<p>£{{plant_price}}</p>
<p>£{{plant_price_from_watch}}</p>
<div v-if="selected.plant && selected.plant.variations.length > 0 ">
<select v-model="selected.plant.selected_variation" class="form-control">
<!-- inline object literal -->
<option v-for="(variation, i) in selected.plant.variations" :selected="variation.id == selected.plant.selected_variation ? 'selected' : ''":value="variation.id">
{{variation.name}}
</option>
</select>
</div>
</div>

Pass vuejs ID to a data-url

I have v-for="product in products"
How i can pass product.id to a data-url?
I try:
<li class="list-group-item" v-for="product in products">
#{{ product.label }}
<input
type="checkbox" :id="product.id" :value="product.id" v-model="product.checked"
class="toggle-product pull-right"
data-url="{{env('APP_URL')}}/accounts/{{ $account->id }} /albums/{{ $album->id }}/images/{{ $image }}/settings/#{{ product.id }}/toggle">
or
data-url="{{route('image.settings.product.toggle',[$account,$album,$image,'product.id'])}}
not work.
$(function () {
// enable/disable products on sidebar
$(".toggle-product").on('click', function () {
var checked = $(this).is(':checked');
var $status = $(this).parents(".list-group-item");
$status.addClass('list-group-item-warning');
$.post($(this).data('url'), {
'enabled': checked ? 1 : 0,
'_token': "{{csrf_token()}}"
}, function (response) {
$status.removeClass('list-group-item-warning');
}.bind(this))
});
});
new Vue({
el: '#products',
data: {
products: [
#foreach($validProducts as $p)
{ label: '{{$p->getTranslatedName()}}', id: '{{$p->id}}', #if(!isset($restrictedProductIds[$p->id])) checked: true #endif},
#endforeach
]
},
computed: {
checked: function (){
return this.products.filter(function (l) {
return l.checked
}).map(function (l){
return l})
}
},
});
Can you help me, thanks.
I know there are two side, server side and client side, but mybe have possible to pass that id ?
Is
:data-url="'{{env('APP_URL')}}/accounts/{{ $account->id }} /albums/{{ $album->id }}
/images/{{ $image }}/settings/' + product.id + '/toggle'">
working ?

Categories