Vue js data logic - booking table - javascript

I need to make a table of bookings (the hours are the y, the slots (actually tennis courts) the x).
I will populate an array from my database with the already occupied
slots (court 5 at 5PM,...);
I'll then loop trough all possibilities (from 7AM to 12PM and for
each hour, every slots) and put the booking's name when taken, and
put a button when it's not.
I can't figure out how to structurate my data;
In Php I had an array like $bookings[$hour][$court] which, when not empty, should contain the booking name (in the php nested loops (hours and courts), I checked if $bookings[$hour][$court] was empty (and then display the content if any or a button otherwise).
I hope I'm clear enough...
Thank you all !
EDIT:
I tried that way:
new Vue({
el: '#app',
data: {
bookings: [
{
hour: '1',
court: '3',
name: 'Laurent'
},
{
hour: '2',
court: '2',
name: 'Gaspard'
}
]
}
})
And
<script src="https://unpkg.com/vue"></script>
<div id="app">
<table>
<tr v-for="hour in (7, 24)" :key="hour">
<td v-for="court in (1,6)" :key="court">
<div v-if="">
</div>
</td>
</tr>
</table>
</div>
But I don't kow how to link the data to the template...

You could create a method that filters the bookings by the court and hour indexes in your loop.
methods: {
getBookings( hour, court ) {
return this.bookings.filter( booking => booking.hour == hour && booking.court == court );
},
},
This returns an array of appointments so I'd use v-for instead of v-if. This means less code in the js, you don't have special code to handle the case where the returned array is empty, and your code will show if you have double bookings.
<div v-for="booking in getBookings( hour, court )" >
{{ booking.name }}
</div>

Related

How to add dynamic array index value in angular html page

I am new to angular I want to add dynamic array index value in html page. I tried different solution I am not getting a solutions. I am not getting any error as well.
I have create a array in typescript as shown below
my typescript
months : string[] = ['January','February','March','April','May','June','July','August','September','October','November','December'];
the above array I want to pass dynamic index value in html page. I tried but I am not getting the value.
I tried like this {{ months[ result.startDate.split('/')[1] ] }} . If i type static index value it is working.
html page
<div class="row" style="width: 110%;" *ngFor="let result of allEvents">
<p class="start-date" >{{ result.startDate.split('/')[0] }} </p> <br><p >{{ months[ result.startDate.split('/')[1] ] }} </p>
</div>
result object I am getting
0:
_id: "5e8b033bd3d04a24db92288a"
name: "Casting call for kannada movie"
description: "Looking for:↵Female artist Age: 17-26↵Kids Age :4-12"
startTime: "6"
endTime: "21"
startDate: "04/04/2020"
endDate: "31/05/2020"
participant: []
userId: "5e536de00d691f6427bcaec1"
pageId: {profileImage: {…}, coverPage: {…}, isBlocked: false, softDelete: false, isVerified: true, …}
createdAt: "2020-04-06T10:23:55.874Z"
updatedAt: "2020-04-06T10:23:55.874Z"
please help me
thanks in advance
That why it is not working. You need to remove 0 from 04 before putting value in the month array.
Parse your index with parseInt before passing it in the month array.
Please see the example below. It is in core JS.
Let me know, If you want it in an angular format I will create a stackblitz example for you
var months = ['January','February','March','April','May','June','July','August','September','October','November','December'];
var result = {};
result.startDate = "04/04/2020";
var key = parseInt(result.startDate.split('/')[1]);
console.log(months[key]);
Please check this link for an example in angular - Example
Try like this:
.html
<p class="start-date" > </p> <br><p>{{getMonthName(result.startDate) }} </p>
.ts
getMonthName(month) {
return this.months[(parseInt(month.split("/")[1])-1)];
}
Working Demo
component.html
<div> {{getMonthName(result.startDate) }} </div>
component.ts
getMonthName(date) {
return this.months[(new Date(date).getMonth())]
}
Another aproach is transfor your object so, startDate and endDate becomes Date
allEvents.forEach(x=>{
x.startDate=new Date(x.startDate)
x.endDate =new Date(x.endDate )
})
And use pipeDate
{{result.startDate| date:'MMM'}}

Can I make an attribute appear only once in a vue v-for

I have an array of people with associated teams. I want to display all the people in the record, but I only want to display their team name once.
Meaning, if the v-for loop has encountered this particular team name, it should put it in a new temporary array to signify that it should be unique, then when it encounters that team name again, checks it through that temporary array and prevent it from showing again.
Sample HTML Code:
<div id="a-list">
<div v-for="person in people">{{person.Name}}, {{person.Team}}</div>
</div>
Sample Vue Code:
var crew = new Vue({
el: "#a-list",
data: {
people:
[ { "Name": "Richard","Team":"DMS"}, { "Name": "Mark","Team":"VV"}, { "Name": "Steve","Team":"VV"}, {"Name":"Koji","Team":"MZ"}, {"Name":"Jamie","Team":"VV"} ]
}
});
Expected Output:
Richard, DMS
Mark, VV
Steve,
Koji, MZ
Jaimie,
Is this possible to do directly from the v-for loop and not in the JS file?
Edited to show more data that are not sequential
Update: As Fabio has pointed out, the above scenario wouldn't make much sense unless the order of the team is arranged sequentially in the output first. So his answer is correct.
This could be a solution:
<div id="a-list">
<div v-for="(person,index) in people"> {{person.Name}}, {{ ((index == 0) || person.Team != people[index-1].Team) ? person.Team : '' }}</div>
</div>

Vue list items not re-rendered on state change

I have some array of object, when user click button I fetch new array and display display some results.
It works fine until I fetch second array. When I fetch first array with one element and then fetch array with two elements it change (add or remove) only second element.
How I change array value:
fetchAsync(result){
this.issue = result.body;
}
How issues looks like?
const issues = [
{
"id":100,
"key":"DEMO-123",
"summary":"Demo issue description",
"devices":[
{
"id":100,
"name":"iPhone6S",
"browsers":[
{
"id":100,
"name":"Safari",
"displayVariants":[
{
"id":100,
"issueKey":"DEMO-123",
"state":1,
"browserName":"safari",
"user":"user-1",
"landScope":false
}
]
}
]
}
]
}
]
and the value which was changed is issues[].devices[].browsers[].displayVariants[].state
How to force Vue to rerender this component when nested change appear?
[ EDIT ]
I render issues like this:
<tr v-for="issue in issues">
<td>
<div>{{ issue.key }}</div>
<div class="issue-description">[ {{ issue.summary }} ]</div>
</td>
<template v-for="d in issue.devices">
<td v-for="browser in d.browsers">
<!--{{ d }}-->
<device v-for="variant in browser.displayVariants"
:variant="variant"
:browserId="browser.id"
:issueKey="issue.key"
:issueId="issue.id"
:deviceId="d.id"></device>
</td>
</template>
</tr>
and device template
<template>
<svg viewBox="0 0 30 30" class="mobileSVG" #click="changeState" :class="[state, {landscape: variant.landScope}]">
<use xlink:href="#mobile"/>
</svg>
</template>
I think adding keys to your list will solve the problem:
https://v2.vuejs.org/v2/guide/list.html#key
Vue tries to make minimum changes to the DOM, and think that the first item has not changed, so it is not re-rendered. In your case you already have the id, using that as key should solve the issue.
Vue cannot detect the following changes made to the array.
Here is the documentation.
When you directly set an item with the index, e.g.
vm.items[indexOfItem] = newValue
When you modify the length of the array, e.g. vm.items.length = newLength
vm refers to component instance.
To overcome the limitation 1 do:
Vue.set(items, indexOfItem, newValue)
For limitation 2:
items.splice(newLength)
So in your case you could do
this.$set(this.issues[0].devices[whateverIndex].browsers[anyIndex].displayVariants, indexOfVariant, valueOfVariant)

How do I pass the current item in a for loop to a method in vue.js 2?

I am building (as an exercise) a shopping cart in vue.js 2. I have my shop items and order items stored in my vue data array and a button rendered in a for loop for each shop item to add the item to the order (ex. push).
Here is the section of code that houses my list of items from my shop array in my vue data:
<fieldset>
<legend>Shop</legend>
<section v-if="shop">
<article v-for="(item, index) in shop">
<header><h1>{{ item.title }}</h1></header>
<p>{{ item.description }}</p>
<footer>
<ul>
<li>${{item.price}}</li>
<!-- find a way to set input name -->
<li><label>Quantity <input type="number" name=""></label></li>
<li><button v-on:click="addItemToOrder($event)">Add to Order</button></li>
</ul>
</footer>
</article>
</section>
<p v-else>No Items to Display</p>
</fieldset>
here is my vue element:
new Vue({
el: '#my-order',
data:{
'shop':[
{
'title':'Website Content',
'description':"Order your Website content by the page. Our search-engine-optimized web content puts you ahead of the competition. 250 words.",
'price':25,
'sku':'web001'
},
{
'title':'Blog Post',
'description':"We write blog posts that position your website as a go-to resource for expert knowlegde.",
'price':50,
'sku':'blog001'
},
{
'title':'Twitter Post'
},
{
'title':'Product Description'
}
],
'customizations':null,
'order':{
'items':null,
'total':null
},
'customer':null,
'payment':null
},
methods:{
addItemToOrder: function(){
/* Here is where I need to append the item to the cart */
}
}
})
How do I pass the item in the for loop to the order (eg: append it to order.items)?
You just need to pass the item in as a parameter to the function.
v-on:click="addItemToOrder(item)"
Then you can use it your Vue component
addItemToOrder: function(item){
this.order.items.push(item);
}
Make sure you initialize order.items to an empty array inside your components data so that you can push to it.
'order':{
'items': [],
'total': 0
},
In general, it is a good idea to initialize your data to the correct data type if you know what it will be.
I realise this is a bit late however in case anyone else happens across this thread...
You need to pass in the event as well as the item
in your vue code
someMethod : function(e, item){}
in your html
<a v-on:click="someMethod($event, $data)"></a>

Add class in angular on ng-repeat when item is contained on array

On an Angular controller I have an array of events:
vm.events = [
{ date: "18-02-2016", name: "event A" },
{ date: "18-02-2016", name: "event C" },
{ date: "24-02-2016", name: "event D" }
];
And I have an array of all days in current month:
var days = [
{ date: "01-02-2016" },
{ date: "02-02-2016" },
{ date: "03-02-2016" }
...
];
On my angular view I have the following:
<span
class="day"
ng-class="{ 'today': isToday(day) }"
ng-repeat="day in vm.days">{{getDay(day)}}</span>
How can I add a class to the span when a day has events, e.g., when the day has at least one record in vm.events?
Here is your solution:
<div ng-repeat="day in days">
<span ng-class="{true:'today', false: 'day' } [isToday(day.date)]">
{{day.date}} : {{isToday(day.date)}}
</span>
</div>
Check the working plunker
You can use ngClass, the way to do is by adding your condition like:
ng-class="{true:'today'}[isToday(day)]"
The first thought might be to write some function that takes a date and then and it determines if that dates has any events by iterating over the events array.
That will result in a lot of unnecessary iteration on each digest cycle. Instead, you can manipulate the data before it's rendered in the ng-repeat. Modify the data such that each day has an array of events. Now you can just check if that day's events array contains any events.
Ideally, I would try and change this on the server, so that data came down in such a fashion. But there's no reason the client can't do it. Here's a simple implementation:
angular.forEach(vm.days, function(day) {
// this modifies the day objects in vm.days, if you didn't want to
// do that you could copy them and produce a separate array of days
// with events...
day.events = vm.findEventsFor(day))
});
vm.findEventsFor(day) {
var events = [];
angular.forEach(vm.events, function(event) {
if (event.date === day.date) {
events.push(event);
}
}
return events;
}
Your ng-class might look like this:
ng-class="{today: isToday(day), hasEvents: day.events.length > 0}"

Categories