Vue2 using $set does not fix change detection caveat when using push() on object - vue.js

Following on from this issue: Strange issue with Vue2 child component object v-for list render
I have a function which loops through an array products, which takes certain values and adds them to an object called attributes. I need to use this.$set to update my attributes object to make sure that Vue can detect the update.
My functions look like this:
//// checks if the value exists in the object to avoid adding duplicates
doesItExist: function(key, value) {
for (let i = 0; i < this.attributes[key].length; i++) {
if (this.attributes[key][i] == value) return true;
}
return false;
},
//// if the value does not exist, then add it to the object
pushIfNotExists: function(key, value) {
if (!this.doesItExist(key, value)) { // returns true/false
this.$set(this.attributes[key], key, this.attributes[key].push(value));
}
},
//// main function looping through the original products array to extract attributes
createAttributes: function() {
for (let i = 0; i < this.products.length; i++) {
for (let j = 0; j < this.products[i]['attributes_list'].length; j++) {
let attributeName = this.products[i]['attributes_list'][j]['attribute_name'];
if (!this.attributes[attributeName]) {
this.attributes[attributeName] = new Array();
};
this.pushIfNotExists(attributeName, this.products[i]['attributes_list'][j]['value']);
}
}
console.log(this.attributes); // outputs expected object
},
The problem I have is that in my child component, the attribute data is still not being rendered, which means this must not be working correctly (even though my console log shows the data is there).
Any ideas?
Thanks

Related

add a object to a array in my class

I want to add an object (from a different class) to an array in my class.
When I try to do that I get this
error: 0xC0000005: Access violation writing location
0x0000000000000000
I create the object (to be added) in the main function and I use the push method in the main function to add this object to my Parking_Lot class.
My code:
void Parking_Lot::push(Cars const &car)
{
time_t t = time(NULL);
struct tm Today = *localtime(&t);
if (is_full())
{
printf("Parking lot is full!!\n");
return;
}
if (Today.tm_hour < OpeningT.tm_hour && Today.tm_hour > ClosingT.tm_hour)
{
printf("Parking lot is now closed!!\n");
printf("Opening time: from %02d:%02d to %02d:%02d\n", OpeningT.tm_hour, OpeningT.tm_min, ClosingT.tm_hour, ClosingT.tm_min);
}
else if (Today.tm_hour == OpeningT.tm_hour || Today.tm_hour == ClosingT.tm_hour)
{
if(Today.tm_min > OpeningT.tm_min || Today.tm_min < ClosingT.tm_min) Lot[front++] = car;
else
{
printf("Parking lot is now closed!!\n");
printf("Opening time: from %02d:%02d to %02d:%02d\n", OpeningT.tm_hour, OpeningT.tm_min, ClosingT.tm_hour, ClosingT.tm_min);
}
}
else if(Today.tm_hour > OpeningT.tm_hour && Today.tm_hour < ClosingT.tm_hour) Lot[front++] = car;
}
where the car is the object I want to add and the Lot is the array in my class that I want to add the object to.
The constructor of my class:
Parking_Lot::Parking_Lot(int s)
{
Cars* Lot = new Cars[s+1];
size = s;
front = 0;
}
What am i doing wrong here and how can I fix it?
The problem is in your constructor:
Parking_Lot::Parking_Lot(int s)
{
Cars* Lot = new Cars[s+1];
size = s;
front = 0;
}
You define a new and separate variable Lot inside the constructor. It will not be related to any possible member variable you might have with the same name.
You need to initialize the member variable instead:
Parking_Lot::Parking_Lot(int s)
{
Lot = new Cars[s+1];
size = s;
front = 0;
}

Enumerating pairs of elements in a Set (Swift 3)

The Swift 3 IteratorProtocol documentation says : "Copying an iterator is safe, but advancing one copy of an iterator by calling its next() method may invalidate other copies of that iterator."
So, this might not work:
var i = set.makeIterator()
while let obji = i.next() {
var j = i
while let objj = j.next() { // Possible error : might invalidate i
...some code...
}
}
So, I wrote this:
var objects = [Object](set)
for i in 0..<objects.count {
for j in (i+1)..<objects.count {
...some code...
}
}
But isn't there a way to do the same thing without copying the set in an array?

Disable specific rows in datagrid/enhancedgrid

I want to disable one specific row in datagrid in following manner:
1) Highlight one row with a different color
2) Disable checkbox/radio button selection of that row
3) Disable inline editing of cells present in that row but allow inline editing for other rows.
Pls. help if you have any ideas.
You can use a combination of the following functions to extract stuff
// as example, one of youre items uses identifier:'id' and 'id:10'
var identifier = '10';
var item = store._arrayOfTopLevelItems[10]; // you probably have this allready
var index = grid.getItemIndex(item); // find which index it has in grid
var rowNode = grid.getRowNode(index); // find a DOM element at that index
You will have the <div> as rowNode, it contains a table with cells (as many as you got columns). Set its background-color
The checkbox thing, you will prly know which cell-index it has
var cellNode = dojo.query('td[idx='+cellIndex+']', rowNode)[0];
// with cellType Bool, td contains an input
var checkbox = cellNode.firstChild;
Editing is another store really.. works in focus handlers. To override it, you must keep like an array of rows which you dont want editable (allthough the cell.editable == true).
function inarray(arr, testVal) {
return dojo.some(arr, function(val) { return val == testVal }).length > 0
}
grid.setNonEditable = function (rowIndex) {
if(! inarray(this.nonEditable,rowIndex) )
this.nonEditable.push(rowIndex);
}
grid.setEditable = function (rowIndex) {
this.nonEditable = dojo.filter(this.nonEditable, function(val) { return val != rowIndex; });
}
var originalApply = grid.onApplyEdit
grid.onApplyEdit = function(inValue, inRowIndex) {
if(! inarray(this.nonEditable,inRowIndex) )
originalApply.apply(this, arguments);
}
If you are using dojox.grid.DataGrid you can use canEdit function to disable row editing or cell editing :
grid = new dojox.grid.DataGrid({
canEdit: function(inCell, inRowIndex) {
var item = this.getItem(inRowIndex);
var value = this.store.getValue(item, "name");
return value == null; // allow edit if value is null
}
}

ExtJS TreeStore update event fire instead of create

I am using tree.Panel with TreeStore when I call
sel_node.parentNode.appendChild(node);
tree.getSampleStore().sync();
ExtJS fire event called sample store proxy: update url instead of create url what could I have done wrong?
What exact version of ExtJS4 do you use?
In my situation, with ext-4.0.7-gpl, I debugged a bit a found out that appendChild method creates a node from and object and then performs some update operations concerning the node's position in the tree, like setting next sibling, parent etc., see [1].
When syncing, the store uses getUpdatedRecords and getNewRecords [2] methods to determine which operation to run. update or create. Somehow, our appended children turn out to be updated, not created.
Note that the method doesn't check whether the children of a parent node was loaded, just pushes the new node into an empty childNodes array; after all these operations end, other children of a parent node are never shown in the tree; and if the update operation caused the serverside generation of new id, the code breaks on the line original = me.tree.getNodeById(record.getId()); - there is no such node with the old id generated on client side..
Simply put, I think it's a bug.
[1] http://docs.sencha.com/ext-js/4-0/source/NodeInterface.html#Ext-data-NodeInterface-method-appendChild
[2] http://docs.sencha.com/ext-js/4-0/source/AbstractStore.html#Ext-data-AbstractStore-method-getUpdatedRecords
Add: ExtJS 4.1 beta 2 doesn't work better for me
Update with temp solution: I hacked a bit and think I solved the issue by overriding the appendChild method of NodeInterface like below (just to set phantom property so that the record becomes created, not updated).
Please note:
1) You should include your appendChild call in the NodeInterface expand method callback, or the bug with pushing to the empty childNodes will remain: the new node will appear somewhere in the wrong place;
2) I had to override updateIndexes of the AbstractView as well, try not to do this and maybe you'll find out why;
3) there are some issues when the store tries to delete our newly created node the next time it syncs - couldn't trace it yet;
0) I am no way ExtJS or even JS guru, so feel free to correct this hack)
Ext.data.NodeInterface.oldGpv = Ext.data.NodeInterface.getPrototypeBody;
Ext.data.NodeInterface.getPrototypeBody = function(){
var ret = Ext.data.NodeInterface.oldGpv.apply(this, arguments);
ret.appendChild = function(node, suppressEvents, suppressNodeUpdate) {
var me = this,
i, ln,
index,
oldParent,
ps;
if (Ext.isArray(node)) {
for (i = 0, ln = node.length; i < ln; i++) {
me.appendChild(node[i]);
}
} else {
node = me.createNode(node);
if (suppressEvents !== true && me.fireEvent("beforeappend", me, node) === false) {
return false;
}
index = me.childNodes.length;
oldParent = node.parentNode;
if (oldParent) {
if (suppressEvents !== true && node.fireEvent("beforemove", node, oldParent, me, index) === false) {
return false;
}
oldParent.removeChild(node, null, false, true);
}else{
node.phantom = true;
}
if(me.isLoaded()){
index = me.childNodes.length;
if (index === 0) {
me.setFirstChild(node);
}
me.childNodes.push(node);
node.parentNode = me;
node.nextSibling = null;
me.setLastChild(node);
ps = me.childNodes[index - 1];
if (ps) {
node.previousSibling = ps;
ps.nextSibling = node;
ps.updateInfo(suppressNodeUpdate);
} else {
node.previousSibling = null;
}
node.updateInfo(suppressNodeUpdate);
}
//console.log('appendChild was called');
// I don't know what this code mean even given the comment
// in ExtJS native source, commented out
// As soon as we append a child to this node, we are loaded
//if (!me.isLoaded()) {
// me.set('loaded', true);
//}
// If this node didnt have any childnodes before, update myself
//else
//if (me.childNodes.length === 1) {
// me.set('loaded', me.isLoaded());
//}
if (suppressEvents !== true) {
me.fireEvent("append", me, node, index);
if (oldParent) {
node.fireEvent("move", node, oldParent, me, index);
}
}
return node;
}
};
return ret;
};
this is my code to add a node by values taken from a form domainForm. The form opens by clicking an icon in an actioncolumn of our tree grid:
var node = grid.store.getAt(rowIndex);
node.expand(false, function(){
var newDomain = domainForm.getValues();
newDomain.parent = {id: node.raw.id}; // i don't know whether you'll need this
var newNode = node.appendChild(newDomain);
me.store.sync();
});
and updateIndexes overrider:
Ext.override(Ext.view.AbstractView, {
updateIndexes : function(startIndex, endIndex) {
var ns = this.all.elements,
records = this.store.getRange(),
i;
startIndex = startIndex || 0;
endIndex = endIndex || ((endIndex === 0) ? 0 : (ns.length < records.length?(ns.length - 1):records.length-1) );
for(i = startIndex; i <= endIndex; i++){
ns[i].viewIndex = i;
ns[i].viewRecordId = records[i].internalId;
if (!ns[i].boundView) {
ns[i].boundView = this.id;
}
}
}
});
Had the same issue, an update to ext-4.1.0-beta-2 fixed it.
The reason might be wrong format of data that comes from the server in response to your request.
Syncronization doesn't happen. Pass 'success' key with the value of TRUE in the server response.
Hmm ... try this ...
beforeitemexpand(node, eOpts){
if (node.data.expanded) return false
}

JScript.NET private variables

I'm wondering about JScript.NET private variables. Please take a look on the following code:
import System;
import System.Windows.Forms;
import System.Drawing;
var jsPDF = function(){
var state = 0;
var beginPage = function(){
state = 2;
out('beginPage');
}
var out = function(text){
if(state == 2){
var st = 3;
}
MessageBox.Show(text + ' ' + state);
}
var addHeader = function(){
out('header');
}
return {
endDocument: function(){
state = 1;
addHeader();
out('endDocument');
},
beginDocument: function(){
beginPage();
}
}
}
var j = new jsPDF();
j.beginDocument();
j.endDocument();
Output:
beginPage 2
header 2
endDocument 2
if I run the same script in any browser, the output is:
beginPage 2
header 1
endDocument 1
Why it is so??
Thanks,
Paul.
Just a guess, but it appears that JScript.NET doesn't support closures the same way as EMCAScript, so the state variable in endDocument() isn't referencing the private member of the outer function, but rather an local variable (undeclared). Odd.
You don't have to use new when calling jsPDF here since you're using a singleton pattern. jsPDF is returning an object literal so even without new you'll have access to the beginPage and endDocument methods. To be perfectly honest I don't know what the specifications call for when using new on a function that returns an object literal so I'm not sure if JScript.NET is getting it wrong or the browser. But for now try either getting rid of the new before jsPDF() or change your function to this:
var jsPDF = function(){
var state = 0;
var beginPage = function(){
state = 2;
out('beginPage');
};
var out = function(text){
if(state == 2){
var st = 3;
}
MessageBox.Show(text + ' ' + state);
};
var addHeader = function(){
out('header');
};
this.endDocument = function(){
state = 1;
addHeader();
out('endDocument');
};
this.beginDocument: function(){
beginPage();
};
}
That will allow you to use the new keyword and create more than one jsPDF object.
I've come across the same problem. In the following code, the closure bound to fun should contain only one variable called result. As the code stands, the variable result in the function with one parameter seems to be different to the result variable in the closure.
If in this function the line
result = [];
is removed, then the result in the line
return result;
refers to the result in the closure.
var fun = function() {
var result = [];
// recursive descent, collects property names of obj
// dummy parameter does nothing
var funAux = function(obj, pathToObj, dummy) {
if (typeof obj === "object") {
for (var propName in obj) {
if (obj.hasOwnProperty(propName)) {
funAux(obj[propName], pathToObj.concat(propName), dummy);
}
}
}
else {
// at leaf property, save path to leaf
result.push(pathToObj);
}
}
return function(obj) {
// remove line below and `result' 3 lines below is `result' in closure
result = []; // does not appear to be bound to `result' above
funAux(obj, [], "dummy");
return result; // if result 2 lines above is set, result is closure is a different variable
};
}();