Dom-repeat not re-rendering when Array sorts - polymer-2.x

I have an array property:
arrayList: {
type: Array,
value:[
{id:"1",candy:"Reeces"},
{id:"1",candy:"M&M"},
{id:"1",candy:"KitKat"},
{id:"1",candy:"Twizzlers"}
]
}
and a boolean property
forceRerender: {
type: Boolean,
value: false
}
I call them in a Dom-Repeat to populate the HTML:
<template is="dom-repeat" as="candy" items="[[getCandyList(arrayList, forceRerender)]]">
<div id="[[candy.id]]" class="candy-row" data="[[candy]]" on-tap="selectCandy">
</template>
The selectCandy() function looks like this:
selectCandy(event) {
let arr = this.arrayList;
for(let j = 0, i = 0; j < arr.length; j++) {
if(arr[j].select) {
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
}
}
this.set('forceRerender', !this.forceRerender);
}
And my getter:
getCandyList(arr,forceRerender) {
return arr;
}
My selectCandy() effectively rearranges the arrayList, but does not visually update the HTML content to represent this. I can't seem to figure out why.
I've made a separate array and used that to change values. I've made a local array and pushed to that and returned it. I've rewritten the order in which things are done. Separated the sections up multiple times to review each portion individually.
I've been at this for at least 3 hours and I'm lost. Can't anyone explain to me here what I'm doing wrong?

This below example could give you some inspiration. As far as I understood, you want to move up (top) the selected item.
Demo
<template is="dom-repeat" items="[[getCandyList(arrayList, forceRerender)]]" as="candy">
<paper-item on-tap="selectCandy"> <div id="[[candy.id]]" class="candy-row" data="[[candy]]"> [[candy.id]] - [[candy.candy]]</div>
</paper-item>
</template>
And the Js may look like:
selectCandy(e) {
let temp = this.arrayList;
//In order to observable change in dom-repeat
this.set('arrayList', []);
temp.splice(e.model.index, 1);
temp.unshift(e.model.candy);
this.set("arrayList", temp);
this.set('forceRerender', !this.forceRerender);
}
You may re-organize the array with other types.

I have discovered the solution:
getCandyList(arr,forceRerender) {
let rowList = [];
for(let j = 0, i = 0; j < arr.length; j++) {
if(arr[j].select) {
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
}
}
arr.forEach(function(object) {
rowList.push(object);
}.bind(this));
return rowList;
}
and
selectCandy(event) {
this.set('forceRerender', !this.forceRerender);
}
moral of the story here is do all the stuff you wanna do to your objects and arrays in the get function.

Related

Clear JQuery DataTable Local Storage

How to clear Jquery Datatable Local Storage programmatically?
localstorage.clear() clears all localstorage.
But I need to clear the datatable values specifically.
<i class="fas fa-sync-alt RefreshButtonDataTable" onclick="ClearDataTableStorageAndRefresh()"></i>
<script>
function ClearDataTableStorageAndRefresh() {
ClearLocalStorageDataTables_tbl();
$('#tbl_SearchTasks').DataTable().ajax.reload();
}
</script>
function ClearLocalStorageDataTables_tbl() {
debugger;
var arr = []; // Array to hold the keys
// Iterate over localStorage and insert the keys that meet the condition into arr
for (var i = 0; i < localStorage.length; i++) {
if (localStorage.key(i).substring(0, 14) == 'DataTables_tbl') {
arr.push(localStorage.key(i));
}
}
// Iterate over arr and remove the items by key
for (var i = 0; i < arr.length; i++) {
localStorage.removeItem(arr[i]);
}
new Noty({
type: 'success',
theme: 'metroui',
layout: 'bottomRight',
text: 'Datatable Temporary Storage Cleared',
progressBar: true,
timeout: 5000
}).show();
}

Vue.js list not updating when data changes

i'm trying re-organised a list of data. I have given each li a unique key, but still, no luck!
I have had this working before exactly like below, think i'm cracking up!
let app = new Vue({
el: '#app',
data: {
list: [
{ value: 'item 1', id: '43234r' },
{ value: 'item 2', id: '32rsdf' },
{ value: 'item 3', id: 'fdsfsdf' },
{ value: 'item 4', id: 'sdfg543' }
]
},
methods: {
randomise: function() {
let input = this.list;
for (let i = input.length-1; i >=0; i--) {
let randomIndex = Math.floor(Math.random()*(i+1));
let itemAtIndex = input[randomIndex];
input[randomIndex] = input[i];
input[i] = itemAtIndex;
}
this.list = input;
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<ul>
<li v-for="item in list" :key="item.id">{{ item.value }}</li>
</ul>
Randomize
</div>
Edit:
Thanks for the answers, to be honest the example I provided may not have been the best for my actual issue I was trying to solve. I think I may have found the cause of my issue.
I'm basically using a similar logic as above, except i'm moving an array of objects around based on drag and drop, this works fine with normal HTML.
However, i'm using my drag and drop component somewhere else, which contains ANOTHER component and this is where things seem to fall apart...
Would having a component within another component stop Vue from re-rendering when an item is moved within it's data?
Below is my DraggableBase component, which I extend from:
<script>
export default {
data: function() {
return {
dragStartClass: 'drag-start',
dragEnterClass: 'drag-enter',
activeIndex: null
}
},
methods: {
setClass: function(dragStatus) {
switch (dragStatus) {
case 0:
return null;
case 1:
return this.dragStartClass;
case 2:
return this.dragEnterClass;
case 3:
return this.dragStartClass + ' ' + this.dragEnterClass;
}
},
onDragStart: function(event, index) {
event.stopPropagation();
this.activeIndex = index;
this.data.data[index].dragCurrent = true;
this.data.data[index].dragStatus = 3;
},
onDragLeave: function(event, index) {
this.data.data[index].counter--;
if (this.data.data[index].counter !== 0) return;
if (this.data.data[index].dragStatus === 3) {
this.data.data[index].dragStatus = 1;
return;
}
this.data.data[index].dragStatus = 0;
},
onDragEnter: function(event, index) {
this.data.data[index].counter++;
if (this.data.data[index].dragCurrent) {
this.data.data[index].dragStatus = 3;
return;
}
this.data.data[index].dragStatus = 2;
},
onDragOver: function(event, index) {
if (event.preventDefault) {
event.preventDefault();
}
event.dataTransfer.dropEffect = 'move';
return false;
},
onDragEnd: function(event, index) {
this.data.data[index].dragStatus = 0;
this.data.data[index].dragCurrent = false;
},
onDrop: function(event, index) {
if (event.stopPropagation) {
event.stopPropagation();
}
if (this.activeIndex !== index) {
this.data.data = this.array_move(this.data.data, this.activeIndex, index);
}
for (let index in this.data.data) {
if (!this.data.data.hasOwnProperty(index)) continue;
this.data.data[index].dragStatus = 0;
this.data.data[index].counter = 0;
this.data.data[index].dragCurrent = false;
}
return false;
},
array_move: function(arr, old_index, new_index) {
if (new_index >= arr.length) {
let k = new_index - arr.length + 1;
while (k--) {
arr.push(undefined);
}
}
arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
return arr; // for testing
}
}
}
</script>
Edit 2
Figured it out! Using the loop index worked fine before, however this doesn't appear to be the case this time!
I changed the v-bind:key to use the database ID and this solved the issue!
There are some Caveats with arrays
Due to limitations in JavaScript, Vue cannot detect the following changes to an array:
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
To overcome caveat 1, both of the following will accomplish the same as vm.items[indexOfItem] = newValue, but will also trigger state updates in the reactivity system:
Vue.set(vm.items, indexOfItem, newValue)
Or in your case
randomise: function() {
let input = this.list;
for (let i = input.length-1; i >=0; i--) {
let randomIndex = Math.floor(Math.random()*(i+1));
let itemAtIndex = input[randomIndex];
Vue.set(input, randomIndex, input[i]);
Vue.set(input, i, itemAtIndex);
}
this.list = input;
}
Here is an working example: Randomize items fiddle
Basically I changed the logic of your randomize function to this:
randomize() {
let new_list = []
const old_list = [...this.list] //we don't need to copy, but just to be sure for any future update
while (new_list.length < 4) {
const new_item = old_list[this.get_random_number()]
const exists = new_list.findIndex(item => item.id === new_item.id)
if (!~exists) { //if the new item does not exists in the new randomize list add it
new_list.push(new_item)
}
}
this.list = new_list //update the old list with the new one
},
get_random_number() { //returns a random number from 0 to 3
return Math.floor(Math.random() * 4)
}
randomise: function() { let input = this.list;
for (let i = input.length-1; i >=0; i--) {
let randomIndex = Math.floor(Math.random()*(i+1));
let itemAtIndex = this.list[randomIndex];
Vue.set(this.list,randomIndex,this.list[i])
this.list[randomIndex] = this.list[i];
this.list[i] = itemAtIndex;
} this.list = input;
}
Array change detection is a bit tricky in Vue. Most of the in place
array methods are working as expected (i.e. doing a splice in your
$data.names array would work), but assigining values directly (i.e.
$data.names[0] = 'Joe') would not update the reactively rendered
components. Depending on how you process the server side results you
might need to think about these options described in the in vue
documentation: Array Change Detection.
Some ideas to explore:
using the v-bind:key="some_id" to have better using the push to add
new elements using Vue.set(example1.items, indexOfItem, newValue)
(also mentioned by Artokun)
Source
Note that it works but im busy so i cant optimize it, but its a little bit too complicted, i Edit it further tomorrow.
Since Vue.js has some caveats detecting array modification as other answers to this question highlight, you can just make a shallow copy of array before randomazing it:
randomise: function() {
// make shallow copy
let input = this.list.map(function(item) {
return item;
});
for (let i = input.length-1; i >=0; i--) {
let randomIndex = Math.floor(Math.random()*(i+1));
let itemAtIndex = input[randomIndex];
input[randomIndex] = input[i];
input[i] = itemAtIndex;
}
this.list = input;
}

Reading from an object

I want to retrieve the values of marked dates how can I get all the marked dates where marked value is true from this object:
alert(JSON.stringify(this.state._markedDates))
{"2018-09-26":{"marked":true}, "2018-09-27":{"marked":false}, "2018-09-29":{"marked":true}}
Expected Result :
{"2018-09-26","2018-09-29"}
I tried the following but datelist is still empty:
for(var i=0; i<this.state._markedDates.length ; i++)
{
if(this.state._markedDates[i].marked == true)
{
this.state.datesList.push(_markedDates[i])
}
}
let dates = {
"2018-09-26":{"marked":true},
"2018-09-27":{"marked":false},
"2018-09-29":{"marked":true}
}
let markedDates=[];
Object.keys(dates).map(date => {
if(dates[date].marked){ markedDates.push(date)}
})
console.log(markedDates)
There are different ways of approaching this, you could filter them for example as below:
let dates = ["2018-09-26":{"marked":true}, "2018-09-27":{"marked":false}, "2018-09-29":{"marked":true}];
let filtered = dates.filter( date => {
if(date.marked === true) {
return date;
}
});
// filtered = {"2018-09-26":{"marked":true}, "2018-09-29":{"marked":true}};
This is how you can get all of the dates where marked = true.
Then you can do
let keyNames = Object.keys(filtered);
console.log(keyNames); // Outputs ["2018-09-26","2018-09-29"]
As a for loop
let markedDates = [];
for(var i=0; i<this.state._markedDates.length; i++)
{
if(this.state._markedDates[i].marked === true)
{
markedDates.push(_markedDates[i])
}
}
this.setState({ObjectIWantToSet: markedDates})
let dates = []
let obj = {"2018-09-26":{"marked":true}, "2018-09-27":{"marked":false}, "2018-09-29":{"marked":true}}
for(date in obj)
{
if(a[date]["marked"])
{
dates.push(date)
}
}
console.log(dates)

How can i use computed property in v-for

I penerate list for vue,second list in wrapper,left and right,
computed: {
currentIndex () {
for (let i = 0; i < this.listHeight.length; i++) {
let height1 = this.listHeight[i];
console.log(height1);
let height2 = this.listHeight[i + 1];
if (!height1 || (this.scrollY < height1 && this.ScrollY >= height2)) {
return i;
}
}
return 0;
}
this code have a question,height1 and height2 not movement,why is regular two variable inner loop.
like this:
<span v-for="(index,key) in currentIndex" :key="key">
{{index}}
</span>
you should edit element and content depending on what do you want to do in your template.

results.row[i] is undefined using react-native-db-models

Im new to React Native and Im using react-native-db-models. I have searched stackoverflow for fetching the data and it gave me this code below
DB.users.get_all((result) => {
let data = [];
for (let i = 1; i <= result.totalrows; i++) {
data.push(result.rows[i]);
}
but result.rows[i] returns undefined. Any ideas how and why?
I tried my own solution but this time it gave me another problem. This is my code
DB.expense.get_all(function(result){
var data = [];
for (let i = 1; i <= result.totalrows; i++) {
let j = result.autoinc;
let id = j - i;
DB.expense.get_id(id, function(results){
data.push(result)
})
}
}
when I put console.log(data) after data.push(result) it works fine. But when I put console.log(data) outside DB.expense.get_id function, console.log(data) returns an empty array.
I really need your help guys