Hi guys I'm trying to build Tree component in Vue, I'm having a little doubt now I have already built a recursive component, similar to this one, but more complex with checkboxes, drag drop etc
https://v2.vuejs.org/v2/examples/tree-view.html
But now I'm looking at some samples online and it looks of them are made by flattening nested json and making a Tree out of it
Like this one:
https://jsfiddle.net/fernando2684/p0k8szvj/43/
Hi here recursive builds array and then builds Tree out of it
recursive(obj, newObj, level, itemId, isExpend) {
let vm = this;
obj.forEach(function(o) {
if (o.children && o.children.length != 0) {
o.level = level;
o.leaf = false;
newObj.push(o);
if (o.id == itemId) {
o.expend = isExpend;
}
if (o.expend == true) {
vm.recursive(o.children, newObj, o.level + 1, itemId, isExpend);
}
} else {
o.level = level;
o.leaf = true;
newObj.push(o);
return false;
}
});
},
Could someone tell, what could be real benefit out of this, I see it could be easier to maintain and all the data in array is reactive since it is only in one level ???
It's a matter of optimizing the data for use in the template.
Flat array
If you're rendering a table, using recursive components will be difficult to implement.
If you have an array, you can pass it through a v-for and you end up with a single component that has all the children (no matter the depth) as direct children. This makes controlling actions easier.
Nested Object
But if you want to use divs that recursively indent, then using a flat array is more difficult.
If you were to use objects, you would have to use recursive components with their individual parent-child relationships that need to bubble up.
Do which ever suits you better, but don't think optimizing data for template is worse than creating more complex component relationships.
Related
So I created a property in the root element of my qml and filled it with JavaScript as a 2d array. I did it this way:
property var cars: {
var carList = new Array(root.numberOfCars)
for (var i=0;i<root.numberOfCars;i++) {
var carProperties = new Array(numberOfCarProperties);
carProperties[root.currentStation] = -1;
carProperties[root.score] = 100;
carProperties[root.numberOfErrors] = 0;
carProperties[root.hasProblem] = false;
carProperties[root.errorScore] = 0;
carProperties[root.finished] = false;
carList[i] = carProperties;
}
return carList;
}
The values of the array will be changed as the program runs via JavaScript.
I want to display the values of this 2d array in a table and update them when they're changed, in addition to some action buttons that affect the values of the array at it's own row.
I'm just a noob at QML and programming in general, so if this is a very basic question please tell me where can I learn more, since I've found few resources online to learn QML.
Plain arrays are not the ideal solution if you intend to visualize the data. QML views can use arrays as models, but this is inefficient if you want to reflect internal changes. You either have to force update of the entire view, recreating all view delegates instead of just updating the changed value, or you will have to implement your own mechanism to update changes.
The easiest thing to use would be a ListModel element, and rather than implementing properties as an array (bad idea anyway) you can implement them as list element properties:
ListModel {
id: carList
ListElement {
currentStation: -1
score: 100
numberOfErrors: 0
// ...
}
ListElement {
// ...
}
}
The model can be populated declarative as above, or imperatively:
carList.append({"currentStation": -1, "score": 100, ...})
You also have the usual index access, property access and so on, just scroll through the doc to get an idea of the interface.
The benefit of this is you will get efficient automatic updates in the view. So you just set up a view and implement a delegate that will serve to visualize and manipulate the data.
Are there any adventage of using linked lists in javascript? Its main adventage over arrays (for example) is that we can insert element at random index without moving every element and that they are not limited to size as arrays.
However, arrays in JS are dynamically expanded, shrink, and arrays are faster to access data. We can also use Array.prototype.splice() method (indeed linked lists could be still faster than this one) to insert data.
Are there any advantages (speed and so on) of using linked lists over arrays in JavaScript then?
Code of basic linked lists using JS.
function list() {
this.head = null;
this.tail = null;
this.createNode=function(data) {
return {data: data, next: null }
};
this.addNode=function(data) {
if (this.head == null) {
this.tail = this.createNode(data);
this.head = this.tail;
} else {
this.tail.next = this.createNode(data);
this.tail = this.tail.next;
}
};
this.printNode=function() {
var x = this.head;
while (x != null) {
console.log(x.data);
x = x.next;
}
}
}
var list = new list();
list.addNode("one");
list.addNode("two");
list.printNode();
In a linked list if you are prepending or appending elements at the front or at the back then the time complexity is O(1), however it is O(n) for an array. However if you are retrieving an element from an array using the index then the time complexity will be O(1) against the linked list which would be O(n).
So it depends as to what you are trying to do, you need to create benchmarks and then test it as to which operation is taking how much time.
You can check the wiki:
I don't know the performance differences. As you say, linked lists have advantages over arrays in other languages in terms of memory allocation, garbage collection, sparseness, but Javascript arrays handle some of those problems. Nevertheless you still may have reason to use linked lists if your use case calls for that kind of data structure: that is, you only need to reach items starting from the front (or either end with doubly-linked lists) and proceeding from from item to next item, without the need for random access by array index.
Some colorful metaphors about linked lists here: What is a practical, real world example of the Linked List?
So I have a list of items.
Each item has a like or dislike button. I wish to sort it by total score, which is = # likes less # dislikes.
I am trying to understand why:
The below handlebar + sort is not working on client side and how to make it work?
If a server side solution would be better and why? (server side takes up unnecessary disk space from what I have learnt in other posts and premature optimization - Yes, Im still in the early stages)
This is how I store it in the list in items.js within collections (ground 0 form).
var item = _.extend(itemAttributes, {
lovers: [],
likes: 0,
haters: [],
dislikes: 0
//popularity: likes - dislikes I tried inserting in collection but doesnt work too
});
So Im sorting it via a handlebar helper + extension of the main list controller
This is the handlebar segment
Template.registerHelper('popularity', function(likes, dislikes) {
var popularity = likes - dislikes;
return popularity;
This is the sorter in router.js
BestItemController = ItemListController.extend({
sort: {popularity: -1},
nextPath: function() {
return Router.routes.BestItem.path({itemsLimit: this.itemsLimit() + this.increment})
}
});
So the handlebar popularity calculations actually does work, the popularity score appears on addition of {{ popularity 123numbersxx }}
However the sorting doesnt work, probably because the sorting does not sort "on the surface" calculations, but rather on the actual item and its fields?
I tried to insert an additional schema field (see above commented line). However that causes errors which states likes are not defined.
Would anyone help guide me a little on this?
Also if you think my method of doing things is bad, appreciate any other ways? For example if sorting on the individual template helper.js files rather than on the main router.js files.
Many thanks!
You can achieve that client-side. Here is how I would proceed:
You probably display your item to be sorted using an {{#each item}} iteration. I would replace item in the #each by a custom helper and create a function, using a cursor or an array as an argument, that will sort your items using the current sorting settings.
Your helper could look like that:
Template.items.helpers({
sortedItems: function(){
return sortMyItems(items.find()) //add .fetch() if you need an array,
//or directly your array if you already have it in a variable.
}
});
And at the beginning of your file, you add the sortMyItems function where you return the sorted list of items.
sortMyItems = function(cursor) {
if(!cursor) {
return [];
}
var sortBy = Session.get("sortBy");// in your case, it would be set to "popularity"
var sortAscending = Session.get("sortAscending ");
if(typeof(sortAscending) == "undefined") sortAscending = true;
var sorted = [];
var raw = cursor.fetch();
// sort
if(sortBy) {
sorted= _.sortBy(raw, sortBy);
// descending?
if(!sortAscending) {
sorted= sorted.reverse();
}
}
return sorted;
}
here I use Session vars, but I advise you to rather use reactive variables or reactive dictionary, since this is a feature related to the current view only.
I want to create a diagram with d3.js using the tree layout. Instead of the common flare json structure with hierarchical children like:
{
"name":"bla",
"children":[
{
"name":"bla2",
"someattribute":"green"
}
]
}
I just have an array (of elements which represent a timestep). I always want the next element(s) of the array to be the child(ren) element of the current.
So in fact I want a tree to be generated out of a flattened array.
My idea was to change the children function of the tree layout like this:
var tree = d3.layout.tree()
.children(function(d,i) {
return data[(i+1)];
})
But only one element is displayed in the tree. I don't get it. Shouldn't it iterate over every element when calling tree.nodes on data[0] ?
To clarify my request: I want to turn an array like [ele1, ele2, ele3] into a tree graph that looks like:
ele1-->ele2-->ele3
The real issue I see is that the function passed to .children() needs to return an Array of children Objects, instead of a single Object as it is now, i.e.
var tree = d3.layout.tree()
.children(function(d,i) {
return i < data.length - 1; data.slice(i+1, i+2) : null;
})
It's also important that the leaf node (the last data Object in the array) returns null instead of an empty list.
Using this approach, I created a working JSFiddle that will create a linear tree from an array of objects.
However, I agree with #LarsKotthoff's comment on your post; your code would be better served in terms maintainability and flexibility if you passed tree.nodes() a root of an Object in hierarchical format.
I'm trying to make a little damage calculator for the game Diablo 3 (I know, I know).
Basically the idea is that it has a "before" and "after" array of values that represent items for your character. The "after" array should duplicate the "before" array when that's updated. However, changes to the "after" array should not update the "before" array.
Each array then displays a DPS (more of this is better) total, and it shows you the difference between the two. The idea is then it makes for easy comparison of two items when using the in-game auction house.
I have the first bit set up - the "before" array is working great. However I'm at a loss as to how to create the "after" array, and I'm wondering if I've made this a different magnitude of complexity. Should I be using two view models, replicating it in jQuery, or using the mapping plugin? I can't quite find anything that's exactly what I'm after, the UI requirements especially seem a bit of a sticking point
Fiddle of where I'm up to: http://jsfiddle.net/kimadactyl/GuMuY/8/
Here's a solution that should get you started. I refactored your HeroItem to take a config object and an optional linked Hero.
I am assuming for the moment the array is fixed length. I create the after array from the items array by mapping it to a new HeroItem, using jquery extend to do a deep copy.
When a link is passed in the HeroItem will subscribe to changes on it's observables and update one-way only as specified.
function HeroItem(config, link) {
var self = this, prop;
self.item = config.item;
self.int = ko.observable(config.int);
self.ias = ko.observable(config.ias);
self.critdmg = ko.observable(config.critdmg);
self.critpc = ko.observable(config.critpc);
self.min = ko.observable(config.min);
self.max = ko.observable(config.max);
if (link) {
for (prop in link) {
if (link.hasOwnProperty(prop) && ko.isObservable(link[prop])) {
console.log("subscribing " + prop);
link[prop].subscribe((function(p) {
return function (newValue) {
console.log("updating " + p+ " to " + newValue);
self[p](newValue);
}
})(prop));
}
}
}
}
self.after = ko.observableArray(ko.utils.arrayMap(self.items(), function(i) {
return new HeroItem($.extend({}, ko.toJS(i)), i);
}));
http://jsfiddle.net/madcapnmckay/2MNFn/1/
No custom bindings needed, it just uses the subscription capabilities all KO observables have. If you want to extend this to cope with dynamic length arrays simple subscribe to the items array and cleanup the after array accordingly.
Hope this helps.