Updating element on firebase binded array on vueJs - javascript

I have this Orders array and on the inner div order, I check which status it has.
<div class="list-group" v-for="(order, key) in orders">
<div class="order" v-if="checkOrderStatus(order.status)">
<div class="dishes">
<ul id="dishes" v-for="dish in order.dishes" >
<li v-if="checkDishOnOrder(dish)">{{checkDishOnOrder(dish).quantity}} x {{checkDishOnOrder(dish).dishName}}</li>
</ul>
</div>
<div class="notInclude">
<ul id="notInclude" v-for="dish in order.dishes" >
<li v-if="checkForNotInclude(dish)">{{checkForNotInclude(dish)}}</li>
</ul>
</div>
<div class="table">
<center><span id="table">{{order.tableID}}</span></center>
</div>
<div class="hour">
<center><span id="hour">{{order.hour}}</span></center>
</div>
<div class="status">
<center><button type="button" id="status" :class="{'doingOrder' : order.status == 'Pedido pronto', 'orderDone' : order.status == 'Pronto para entrega'}" #click="changeStatus(order)">{{order.status}}</button></center>
</div>
</div>
</div>
On the beforeCreate: I binded this array with a firebase ref:
this.$bindAsArray('orders', database.ref('orders/' + user.uid).orderByChild('hourOrder'))
The problem is, every time I change a order status the last element of the array changes together and it should not happen.
Here is my checkOrderStatus: function:
checkOrderStatus: function(orderStatus) {
if(this.orderType == 'Em andamento') {
if(orderStatus != "Pronto para entrega") {
return true
}
} else if (this.orderType == 'Pedidos feitos') {
if(orderStatus == "Pronto para entrega") {
return true
}
}
},
Here is changeStatus: function:
changeStatus: function(order) {
var that = this;
var database = Firebase.database();
var loggedUser = Firebase.auth().currentUser;
if (order.status == 'Em andamento') {
order.status = 'Pedido pronto';
var orderKey = order['.key'];
delete order['.key'];
var updates = {};
updates['orders/' + loggedUser.uid + '/'+ orderKey] = order;
database.ref().update(updates).then(function() {
console.log('order Updated');
})
}
else if(order.status == 'Pedido pronto') {
order.status = 'Pronto para entrega';
var orderKey = order['.key'];
delete order['.key'];
var updates = {};
updates['orders/' + loggedUser.uid + '/'+ orderKey] = order;
database.ref().update(updates).then(function() {
console.log('order Updated');
})
}
},

I found a way to avoid this behavior using computed properties:
computed: {
fixedOrders() {
var database = Firebase.database();
this.$bindAsArray('orders', database.ref('orders/' + this.userID).orderByChild('hourOrder'))
return this.orders
},
}
I've binded the array again on a computed property, so that way it always have the right values for orders.
I'm just concerned about the performance loss because I'm biding the orders array again every time it changes.

Related

Update quantity of items in cart without pushing entirety of object in JS

I'm having a bit of trouble with this problem. I'm working on the project of an e-commerce application that works on several html pages. I managed to push products through the cart html page, but I can't seem to find a way to update on this page only the quantity of a product and not push every elements of said product (images, id, etc). Onclick, if product exists, I only want quantity to be updated. Here's the code if any of you can help me out that'd be greatly appreciated.
setItems(kanap);
function setItems(kanap) {
let cart = JSON.parse(localStorage.getItem('cart'));
let imgKanap = kanap.imageUrl;
let idKanap = kanap._id;
let colorKanap = colors.value;
let quantityKanap = parseInt(quantity.value);
let key = idKanap + ' ' + colorKanap;
let cartItem = {
id: idKanap,
color: colorKanap,
quantity: quantityKanap,
kanap: kanap
};
if (cart === null) {
cart = [];
}
cart.push(cartItem);
localStorage.setItem('cart', JSON.stringify(cart));
function addProduct(cartItem) {
var found = false;
for (key in cartItem) {
if (cartItem[key].idKanap == idKanap) {
cartItem[key].quantityKanap += quantityKanap;
found = true;
break;
}
}
if (!found) {
cart.push(cartItem);
}
}
addProduct();
}
<div class="item__content__addButton">
<button id="addToCart" type="submit">Ajouter au panier</button>
</div>
<section class="cart">
<!-- <section id="cart__items">
<article class="cart__item" data-id="{product-ID}">
<div class="cart__item__img">
<img id ="image" alt="Photographie dun canapé">
</div>
<div class="cart__item__content">
<div class="cart__item__content__titlePrice">
<h2 class=title></h2>
<p class =price></p>
</div>
<div class="cart__item__content__settings">
<div class="cart__item__content__settings__quantity">
<p class= quantity>Qté : </p>
<input type="number" class="itemQuantity" name="itemQuantity" min="1" max="100" value="">
</div>
<div class="cart__item__content__settings__delete">
<p class="deleteItem">Supprimer</p>
</div>
</div>
</div>
</article> -->
</section>
There's a few approaches you can take, but I am using .find to look through your cart.
If the .find() function finds an item with the same id as you're about to add, it will up the quantity of the existing item instead of appending another object with the same ID.
I used a mock local storage since local storage doesn't work in these snippets so just ignore that and use what you've been doing for local storage access.
let mockLS = null;
// guessed at the structure here, you may have something slightly different
const exampleItem = {
_id: "abc",
imageUrl: "imageurlexample",
colors: {
value: "red"
},
quantity: {
value: 1
}
}
const exampleItem2 = {
_id: "abc2",
imageUrl: "imageurlexample2",
colors: {
value: "blue"
},
quantity: {
value: 1
}
}
function setItems(kanap) {
//let cart = JSON.parse(localStorage.getItem('cart'));
// using a mock localstorage here since it doesn't work within this snippet, use what you currently have instead
let cart = mockLS;
let imgKanap = kanap.imageUrl;
let idKanap = kanap._id;
let colorKanap = kanap.colors.value;
let quantityKanap = parseInt(kanap.quantity.value);
let key = idKanap + ' ' + colorKanap;
let cartItem = {
id: idKanap,
color: colorKanap,
quantity: quantityKanap
//kanap: kanap not sure why you want the whole obj here so I left this one out
};
if (cart === null) {
cart = [];
}
// here is the case where cart exists and there may be the same item in it
const itemExists = cart.find(item => {
if(item.id === idKanap) {
item.quantity += quantityKanap;
return true;
}
return false;
})
if (!itemExists) {
cart.push(cartItem);
}
//localStorage.setItem('cart', JSON.stringify(cart));
mockLS = cart;
}
setItems(exampleItem);
setItems(exampleItem2);
setItems(exampleItem);
console.log(mockLS)

Already known weather for city should not repeat again

I'm trying my first weather api APP. Here I'm trying to achive that if the city weather is already displayed , It should give the message "You already know the weather" . and should not repeat the weather
Here is my code. Anyone Please look at my code ...
What is the mistake I have been made.
<div class="main">
<div class="container">
<div class="search_por">
<h2>Weather </h2>
<div class="validate_msg color_white"></div>
<form>
<label for=""></label>
<input type="search" class="input_text" value="">
<button type="submit" id="sub_button" class="srh_button">Search</button>
</form>
<!-- <canvas id="icon1" width="150" height="75"></canvas> -->
<div class="dat_weather">
<ul id="list_it">
</ul>
</div>
</div>
</div>
</div>
var get_text=document.querySelector("form");
get_text.addEventListener("submit",e=>{
e.preventDefault();
var input_val=document.querySelector('input').value;
const apiKey="bc4c7e7826d2178054ee88fe00737da0";
const url=`https://api.openweathermap.org/data/2.5/weather?q=${input_val}&appid=${apiKey}&units=metric`;
fetch(url,{method:'GET'})
.then(response=>response.json())
.then(data=>{console.log(data)
const{main,sys,weather,wind}=data;
//icons-end
var error_ms=document.getElementsByClassName("validate_msg")[0];
var iconcode = weather[0].icon;
console.log(iconcode);
var li=document.createElement("Li");
var weatherinfo=`<div class="nameci font_40" data-name="${data.name},${sys.country}"><span>${data.name}</span><sup>${sys.country}</sup></div>
<div class="temp_ic">
<img class="weat_icon" src="http://openweathermap.org/img/w/${iconcode}.png">
<div class="deg">${Math.floor( main.temp )}<sup>o</sup></div>
</div>
<div class="clear">
<div>${weather[0].description}</div>
</div>
`;
li.innerHTML=weatherinfo;
var ulid=document.getElementById("list_it");
ulid.appendChild(li);
var city_name=data.name;
console.log(skycons);
var listitems=document.querySelectorAll('#list_it');
const listArray=Array.from(listitems);
if(listArray.length>0)
{
var filtered_array=listArray.filter(el=>{
let content="";
if(input_val.includes(','))
{
if(input_val.split(',')[1].length>2)
{
alert("hving 2 commos");
inputval=input_val.split(',')[0];
content=el.querySelector(".nameci span").textContent.toLowerCase();
//content=el.querySelector(".nameci").innerHTML.toLowerCase();
//content=inputval.toLowerCase();
}
else
{
content=el.querySelector(".nameci").dataset.name.toLowerCase();
}
alert(filtered_array);
}
else
{
content=el.querySelector(".nameci span").textContent.toLowerCase();
}
console.log(inputval.toLowerCase());
return inputval.toLowerCase();
});
if(filtered_array.length>0)
{
console.log(filtered_array.length);
error_ms.innerHTML="You Already know the weather of this country....";
get_text.reset();
return;
}
}
})
.catch((error)=>{
error_ms.innerHTML="Please Enter a valid city Name";
});
var error_ms=document.getElementsByClassName("validate_msg")[0];
error_ms.innerHTML="";
//var get_text=document.querySelector("form");
get_text.reset();
});
My full code is here:
https://codepen.io/pavisaran/pen/wvJaqBg
Let's try keeping track of a list of displayed locations outside of the callback:
var get_text = document.querySelector("form");
// Keep Track Of Displayed Cities Here Instead
let displayed = [];
get_text.addEventListener("submit", e => {
e.preventDefault();
var input_val = document.querySelector('input').value;
const apiKey = "bc4c7e7826d2178054ee88fe00737da0";
const url = `https://api.openweathermap.org/data/2.5/weather?q=${input_val}&appid=${apiKey}&units=metric`;
fetch(url, {method: 'GET'})
.then(response => response.json())
.then(data => {
var error_ms = document.getElementsByClassName("validate_msg")[0];
const {main, sys, weather, wind, name} = data;
if (displayed.length > 0) {
// Filter Displayed Based on Current vs name from data (response)
const filtered_array = displayed.filter(el => el === name);
if (filtered_array.length > 0) {
error_ms.innerHTML = "You Already know the weather of this country....";
get_text.reset();
return Promise.resolve();
}
}
// Add City To Array of Displayed Cities
displayed.push(name);
// Do Rest of Code to Add New City
var iconcode = weather[0].icon;
var li = document.createElement("Li");
var weatherinfo = `<div class="nameci font_40" data-name="${data.name},${sys.country}"><span>${data.name}</span><sup>${sys.country}</sup></div>
<div class="temp_ic">
<img class="weat_icon" src="http://openweathermap.org/img/w/${iconcode}.png">
<div class="deg">${Math.floor(main.temp)}<sup>o</sup></div>
</div>
<div class="clear">
<div>${weather[0].description}</div>
</div>
`;
li.innerHTML = weatherinfo;
var ulid = document.getElementById("list_it");
ulid.appendChild(li);
})
.catch((error) => {
error_ms.innerHTML = "Please Enter a valid city Name";
});
var error_ms = document.getElementsByClassName("validate_msg")[0];
error_ms.innerHTML = "";
get_text.reset();
});
You have to just check for the value which is coming from api whether it's present on your list or not. you can try this.
li.innerHTML=weatherinfo;
var ulid=document.getElementById("list_it");
var isPresent = false;
var items = ulid.getElementsByTagName("li");
for (var i = 0; i < items.length; i++){
if(items[i].innerHTML == li.innerHTML){
alert("you already know the weather")
isPresent = true;
}
}
if(!isPresent){
ulid.appendChild(li);
}

Load more data using vue js when page is bottom area

I tried to make my Load More data when my page scroll to the bottom. The first thing is I make a div element that I put at the end of the data loop.
<div class="products">
<p>{{ status }}</p>
<div class="product" v-for="(item, index) in items">
<div>
<div class="product-image"><img :src="item.link" alt=""></div>
</div>
<div>
<h4 class="product-title">{{ item.title }}</h4>
<p>Price : {{ price }}</p>
<button class="add-to-cart btn" #click="addItem(index)">Add Item To Cart</button>
</div>
</div>
<div id="product-list-bottom"></div>
</div>
Div element with id product-list-bottom I will detect it using scrollMonitor.js
My default data :
data: {
status: 'Empty product',
total: 0,
items: [],
cart: [],
newSearch: 'anime',
lastSearch: '',
price: STATIC_PRICE,
result: []
}
Inside mounted I detected scroll to bottom :
mounted: function() {
this.onSubmit()
var vueInstance = this
var elem = document.getElementById('product-list-bottom')
var watcher = scrollMonitor.create(elem)
watcher.enterViewport(function() {
vueInstance.appendItems()
})
}
Inside mounted I call onSubmit :
onSubmit: function() {
this.items = ''
this.status = "Searching keyword '" + this.newSearch + "' on server ..."
this.$http.get('/search/'.concat(this.newSearch))
.then(function(response) {
this.lastSearch = this.newSearch,
this.status = 'Find ' + response.data.length + ' data'
this.result = response.data
this.appendItems()
})
}
And inside onSubmit I call appendItems function :
appendItems: function() {
if(this.items.length < this.result.length) {
var start = this.items.length
var end = parseInt(this.items.length + 5)
var append = this.result.slice(start, end)
this.items = this.items.concat(append)
console.log(append)
}
}
All goes well, but when I scroll down I get an error message :
This is because this line :
this.items = this.items.concat(append)
How do I make the data on xxx change (always added five new data from the array) according to the command on the line :
var end = parseInt(this.items.length + 5)
Thanks
it seems '/search/'.concat(this.newSearch) gets evaluated into function and not an actual string value
Try this if you are using babel/webpack
this.$http.get(`/search/`${this.newSearch}`)
Or if not
this.$http.get('/search/' + this.newSearch)
I think since Vue 2.3+ or so you can get this done without any jQuery stuff or any other dependencies:
<style>
.scrollbar{
overflow-y: scroll;
//...
}
.styled-scrollbar::-webkit-scrollbar
.styled-scrollbar::-webkit-scrollbar-thumb
.styled-scrollbar::-webkit-scrollbar-track{
//styling
}
</style>
<template>
//...
<div #scroll="scroll" class="scrollbar">
<div v-for="item in items" :key="item.id">
//TODO: item content
</div
</div>
//...
</template>
<script>
{
data: {
//..
lastScrollUpdate:0
}
//..
mounted: {
scroll:function (e) {
var scrollBar=e.target;
if((scrollBar.scrollTop + scrollBar.clientHeight >= scrollBar.scrollHeight-20)){
var t=new Date().getTime();
if((t-this.lastScrollUpdate)>3000){
this.lastScrollUpdate=t;
console.log('reached end: '+scrollBar.scrollTop+' '+scrollBar.clientHeight+' '+scrollBar.scrollHeight);
//TODO: load more data
}else{
console.log("< 3sec between scoll. no update");
}
}
},
//..
}
}
</script>
You may also want to adjust this to "#scroll.passive", in order to let the scroll-function be executed parallel to the UI (https://v2.vuejs.org/v2/guide/events.html#Event-Modifiers)

Angular Modal - Update the UI (object has moved to another date)

I'm using an Angular UI modal to update the calendar style grid UI. (on a drag and drop style app (using http://marceljuenemann.github.io/angular-drag-and-drop-lists/demo/#/types)), to e.g. change the date of an order planningslot.
The modal is to provide a manual way of updating and I can’t save until the user hits the Save button.
This is fine (though I suspect it could be better) in updating the data in my parent scope object (scope.WokCentres), i.e. the date changes, great). What I’m stuck on is ‘moving’ the object to it’s new date within the 'calendar style grid'
Below is my JS and view html
JS:
$scope.EditWorkOrder = function (slot, max) {
var modalInstance = $uibModal.open({
animation: true,
templateUrl: '/app/WorkOrder/Views/EditWorkOrder.html',
controller: 'EditWorkOrderCtrl as vm',
size: 'lg',
resolve: {
data: function () {
return {
Slot: slot,
Max: max
}
}
}
});
//slotupdate is the returned object from the modal
modalInstance.result.then(function (slotupdate) {
for (var a = 0; a < scope.WorkCentres.length; a++) {
var wcs = scope.WorkCentres[a]
for (var b = 0; b < wcs.WorkOrderDates.length; b++) {
var wcd = wcs.WorkOrderDates[b]
for (var c = 0; c < wcd.PlanningSlots.length; c++) {
var slot = wcd.PlanningSlots[c]
if (slot.Id == slotupdate.Id) {
// This gets hit and updates the appropriate data object from the loop
scope.WorkCentres[a].WorkOrderDates[b].PlanningSlots[c] = slotupdate;
}
}
}
}
}, function () {
// do nothing
// $log.info('Modal dismissed at: ' + new Date());
});
};// END OF MODAL
VIEW:
<div ng-controller="workCentreCtrl as vm">
<div class="row">
<div class="workcentre-left">
<h3>Work Centre</h3>
</div>
<div class="workcentre-right">
<ul>
<li class="date-bar" ng-repeat="workdate in vm.WorkDates">{{workdate |date:'EEEE'}} {{workdate |date:'dd MMM'}}</li>
</ul>
</div>
</div>
<div>
<div class="row" ng-repeat="wc in vm.WorkCentres" ng-model="vm.WorkCentres">
<div class="workcentre-left">
<h5>{{wc.WorkCentreName}}</h5>
<button class="btn btn-default" ng-click="open(wc.WorkCentreId)" type="button">edit</button>
<p ng-if="wc.RouteTime != 0">{{wc.RouteTime}}</p>
</div>
<div class="workcentre-right dndBoxes">
<ul class="orderdate" ng-repeat="date in wc.WorkOrderDates" data-workdate="{{date.OrderDate}}">
<li id="parentorderdate" ng-class="{'four-slot': wc.max == 4, 'eight-slot': wc.max == 8, 'twelve-slot': wc.max == 12,'sixteen-slot': wc.max == 16}">
<ul dnd-list="date.PlanningSlots"
dnd-allowed-types="wc.allowedTypes"
dnd-disable-if="date.PlanningSlots.length >= wc.max"
dnd-dragover="dragoverCallback(event, index, external, type)"
dnd-drop="dropCallback(event, index, item, external, type, 'itemType')"
dnd-inserted="logEvent('Element was inserted at position ' + index, event)">
<li ng-repeat="slot in date.PlanningSlots" ng-model="date.PlanningSlots" ng-if="slot.WorkOrderNumber != '' "
dnd-draggable="slot"
dnd-type="wc.allowedTypes"
dnd-moved="date.PlanningSlots.splice($index, 1)"
dnd-effect-allowed="move" class="slot {{slot.css}}" title="{{slot.WOStatus}}">
<div>{{slot.SlotNumber}}</div>
<div>{{slot.WorkOrderNumber}} - {{slot.ProductDescription}}</div>
<div ng-if="slot.WOStatus != ''"><span class="float-right fa fa-edit fa-2x main-text edit-work-order" ng-click="EditWorkOrder(slot, wc.max)"></span></div>
</li>
<li ng-repeat="slot in date.PlanningSlots" ng-model="date.PlanningSlots" ng-if="slot.SlotBlocked == 'true'"
class="empty-slot">{{slot.SlotBlocked}}
<i class="fa fa-ban fa-2x main-text"></i>
</li>
<li class="dndPlaceholder">Drop work order here
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
Any help many appreciated.
itsdanny
The code in the OP, breaks the model (scope.WorkCentres).
There is an angular.forEach function which doesn't
modalInstance.result.then(function (slotupdate) {
// Remove it
angular.forEach(scope.WorkCentres, function (wc) {
angular.forEach(wc.WorkOrderDates, function (WorkOrderDate) {
angular.forEach(WorkOrderDate.PlanningSlots, function (slot) {
if (slot.Id == slotupdate.Id) {
WorkOrderDate.PlanningSlots.splice(index, 1);
}
})
})
})
// Add it back
angular.forEach(scope.WorkCentres, function (wc) {
if (wc.WorkCentreId == slotupdate.WorkCentreId) {
angular.forEach(wc.WorkOrderDates, function (WorkOrderDate) {
if (WorkOrderDate.OrderDate == slotupdate.OrderDate.getTime()) {
WorkOrderDate.PlanningSlots.push(slotupdate)
return;
}
})
}
})
}
I might actually cry out of joy!

AngularJS: Count while iterating in nested ng-repeat

I have created an angularjs application for printing the Indian people count as well as those who have vote eligible count values,
The application is working fine but i dont know how to get indians and vote eligible counts while iterating
Working Demo
<div ng-app='myApp' ng-controller="Controller">
<div ng-init="indiansCount = 0" ng-repeat="emp in records">
<b>Can Vote :</b><br>
<b>Indians :</b> {{getIndiansCount(emp.country, indiansCount)}}
<div ng-repeat="empl in emp">
{{empl.country}}<br>
{{empl.employee.name}}<br>
{{empl.employee.canVote}}
<hr>
</div>
</div>
</div>
Can anyone please tell me some suggestion for this
Your emp.country is undefined, because emp is a collection of employees. You could do this instead:
HTML:
<b>Indians :</b> {{getIndiansCount(emp, indiansCount)}}
JS:
$scope.getIndiansCount = function(employees, count) {
angular.forEach(employees, function(employee) {
if(employee && employee.country === "Indian") {
count++;
}
});
return count;
};
DEMO
EDIT
In case you don't want to add loops, you can indeed use the ng-repeat to execute an increment function.
First you need to initialize an array for indianCounts (and voteCounts) in your scope:
app.controller('Controller', function ($scope) {
$scope.indiansCount = []; // Like this
$scope.voteCount = [];
...
Then you need these functions:
$scope.initCount = function(i) {
$scope.indiansCount[i] = 0;
$scope.voteCount[i] = 0;
}
$scope.incrementCount = function(empl, i) {
if(empl.country === "Indian") {
$scope.indiansCount[i]++;
}
if(empl.employee && empl.employee.canVote === true) {
$scope.voteCount[i]++;
}
};
Finally, here is the HTML with all the stuff needed:
<div ng-app='myApp' ng-controller="Controller">
<!-- Here you keep a trace of the current $index with i -->
<div ng-init="initCount(i = $index)" ng-repeat="emp in records">
<b>Can Vote :</b> {{voteCount[i]}}<br>
<b>Indians :</b> {{indiansCount[i]}}
<div ng-repeat="empl in emp" ng-init="incrementCount(empl, i)">
{{empl.country}}<br>
{{empl.employee.name}}<br>
{{empl.employee.canVote}}
<hr>
</div>
</div>
</div>
Here is the JSFiddle updated
I have updated you jsFiddle.
Added 3 filters -
1. Indian
2. CanVote
3. IndianCanVote
you can see it working here - http://jsfiddle.net/tmu9kukz/7/
Filters
app.filter("Indian", function() {
return function(records) {
var totalIndianCount = 0;
angular.forEach(records, function(emp, empKey) {
angular.forEach(emp, function(oneEmp, oneEmpKey) {
if (oneEmp.country === "Indian") {
totalIndianCount += 1;
}
});
});
return totalIndianCount;
}
});
app.filter("CanVote", function() {
return function(records) {
var totalCanVote = 0;
angular.forEach(records, function(emp, empKey) {
angular.forEach(emp, function(oneEmp, oneEmpKey) {
if (oneEmp.employee.canVote) {
totalCanVote += 1;
}
});
});
return totalCanVote;
}
});
app.filter("IndianCanVote", function() {
return function(records) {
var totalCanVote = 0;
angular.forEach(records, function(emp, empKey) {
angular.forEach(emp, function(oneEmp, oneEmpKey) {
if (oneEmp.country === "Indian" && oneEmp.employee.canVote) {
totalCanVote += 1;
}
});
});
return totalCanVote;
}
})
HTML
<div> Total Indians : {{records | Indian}} </div>
<div> Total Can Vote : {{records | CanVote}} </div>
<div> Total Can Vote : {{records | IndianCanVote}} </div>

Categories