How to append a child on a specific position (as default the new child will appear after the last node)
My solution is to use a variable of order
function treeGridReorder(){
var i=0 ,j = 0;
treeGrid.getView().getStore().each(function(node){
node.data.ordre=i;
j=0;
node.eachChild(function(cnode){
cnode.data.ordre=j;
j++;
});
i++;
})
}
function add_reponse(quest, qIndex){
questStr.sort('ordre', 'ASC');
var now=new Date().getTime();
questStr.getNodeById(quest).appendChild({id:now, libelle:'Nouvelle réponse',parentq:quest, saved:false, leaf: true});
treeGridReorder()
}
Have you tried : http://docs.sencha.com/ext-js/4-1/#!/api/Ext.data.NodeInterface-method-insertChild ? This takes an index parameter.
Related
I'm not sure why my props aren't updating when I update the data in my parent component. I've tried it out in a fiddle and it works https://jsfiddle.net/f3w69rr6/1/ but it doesn't work in my app.
parent:
methods: {
addToHand(index) {
let card = this.gameState.playerDeck.splice(index, 1)
if (this.gameState.playerHand.length < 12)
{
// put card into hand
this.$set(this.gameState, 'playerHand', [...this.gameState.playerHand, card])
// this.gameState.playerHand.push(card)
}
// otherwise discard card
},
retrieveDeck() {
let array = []
for (let i = 0; i < 20; i++)
{
array.push(this.src + "?text=card"+i)
}
this.$set(this.gameState, 'playerDeck', array)
},
},
mounted () {
this.retrieveDeck()
for (let i = 0; i < 5; i++)
{
this.addToHand(1)
}
},
putting the data into child via:
<PlayerCards :gameState="gameState" :hand="gameState.playerHand" />
child:
export default {
name: 'PlayerCards',
props: ["gameState", "hand"],
data() {
return {
}
},
computed: {
rows() {
let cards = this.gameState.playerHand
let max = 6;
if (cards.length <= max)
return [cards]
var mid = Math.ceil(cards.length / 2);
let return_value = [cards.slice(0, mid), cards.slice(mid)]
return return_value
}
}
}
but the row content is empty.
Update (Updated fiddle):
The problem is with the compute
https://jsfiddle.net/f3w69rr6/1/
If you're not using string templates then you need to use the kebab-case equivalent to your camelCase prop:
<PlayerCards :game-state="gameState" :hand="gameState.playerHand" />
The reason it works in your fiddle is because you are using a string template (see: https://v2.vuejs.org/v2/guide/components.html#camelCase-vs-kebab-case)
Look at your demo in jsfiddle:
rows() {
let cards = this.gameState.playerHand
let max = 6;
if (cards.length <= max)
return [cards]
var mid = Math.ceil(cards.length / 2);
let return_value = [cards.slice(0, mid), cards.slice(mid)]
return return_value
}
Actually, vue has notified the computed function successfully when gameState.playerHand has updated. But you wrapped the computed property: rows into an array, like: [cards] and [cards.slice(0, mid), cards.slice(mid)]. And obviously, the rows.length will be 1 or 2.
I believe this was due to a misuse of the computed property. Switching it over to data and using this.$set updates as expected. If I were to use computed then setters would be needed. Computed also seems to be more suited for combining/updating data properties rather than being a property in and of itself.
The following code has to select items (indirect selection) programmatically, but this only happen in visible part of the table (or first 15 rows). Scrolled items remain unselected.
Is it possible to fix this?
var grid = context._events._gridView;
grid.selection.deselectAll();
var data = jsResponse.message.items;
for (var i = 0; i < data.length; ++i) {
grid.store.fetch({
query: {id: data[i].id},
onComplete: function (items)
{
dojo.forEach(items, function (item, index)
{
console.debug(item.id + "/" + index);
try {
//grid.selection.addToSelection(item);
var idx = grid.getItemIndex(item);
grid.selection.setSelected(idx,true);
}
catch (e) {
console.debug(e);
}
});
}
});
}
Using rowsPerPage, and set it to huge value, helps to work around this bug.
gridView = new dojox.grid.EnhancedGrid({
rowSelector: "20px",
rowsPerPage: plugins.indirectSelection?1500:15,
plugins: plugins
},
document.createElement('div'));
I have dynamically bind a parent's data to a child via dynamic props (objectives is an array which is fetched via AJAX):
<objective-selector :objectives="objectives"></objective-selector>
Inside the objective-selector's ready() hook, I wish to do some pre-processing and somehow this.objectives is an observable, not an array:
Vue.component('objective-selector',{
template: '#objective-selector-template',
data:function() {
return {
current_selected:0
}
},
ready:function(){
// set current selected to the first non-active objective
for (var i =0; i < this.objectives.length; ++i) {
if (this.objectives[i].active == false) {
this.current_selected = i;
break;
}
}
},
props: ['objectives']
});
Everything else works fine (I can use the objectives props as array in the template, for instance). How do I access it as an array inside ready()?
Your ready function is fired sequentially before the ajax response comes back from the server. So you need to fire the function afterward.
One easy way to do this is $broadcast when the value has returned from the parent.
compiled: function(){
this.$on('theDataCameBackFromTheServer',function(){
for (var i =0; i < this.objectives.length; ++i) {
if (this.objectives[i].active == false) {
this.current_selected = i;
break;
}
}
});
}
Another solution would be to use watch (this will fire every time objectives changes):
watch: {
objectives: function(){
for (var i =0; i < this.objectives.length; ++i) {
if (this.objectives[i].active == false) {
this.current_selected = i;
break;
}
}
}
}
I'm relatively new to dojo and have seen how datagrid offers a dynamic filtering capability that reduces the visible rows based on what you type into a filter text input. I have not found any examples of how to do it with the dgrid. If it can be done, please provide an example or point me to a resource that offers a tutorial or example. Thanks!
Yes, it is possible. Use dgrid/OnDemandGrid and define query function that will return true or false based on your logic for each row in dojo/store powering the grid.
I prepared an example to play with at jsFiddle: http://jsfiddle.net/phusick/7gnFd/, so I do not have to explain too much:
The Query Function:
var filterQuery = function(item, index, items) {
var filterString = filter ? filter.get("value") + "" : "";
// early exists
if (filterString.length < 2) return true;
if (!item.Name) return false;
// compare
var name = (item.Name + "").toLowerCase();
if (~name.indexOf(filterString.toLowerCase())) { return true;}
return false;
};
The Grid:
var grid = new Grid({
store: store,
query: filterQuery, // <== the query function for filtering
columns: {
Name: "Name",
Year: "Year",
Artist: "Artist",
Album: "Album",
Genre: "Genre"
}
}, "grid");
I know this isn't the answer to the question asked, and the answer provided is masterful and we use it quite a bit.
However, this functionality doesn't seem to work well at all if you're using a TreeGrid (columns with the "dgrid/tree" plugin). I've written some code to simulate the same behavior as the accepted answer with a tree grid. It's basically just looping through the items in the store and hiding any row elements that don't match whatever condition you set forth. Thought I would share it in case it helps anybody. It's rather ugly and I'm sure it can be improved upon, but it works.
It basically uses the same concept as phusick's answer. You need to watch a value on a TextBox, but instead of refreshing the grid you have it call a function:
textBox.watch("value", lang.hitch(this, function() {
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = null;
};
timeoutId = setTimeout(lang.hitch(this, function() {
this.filterGridByName(textBox.get('value'), myGrid);
}, 300));
}));
And here's the function:
filterGridByName: function(name, grid){
try {
for (var j in grid.store.data){
var dataItem = grid.store.data[j];
var childrenLength = dataItem.children.length;
var childrenHiddenCount = 0;
var parentRow = grid.row(dataItem.id);
for (var k in dataItem.children){
var row = grid.row(dataItem.children[k].id);
var found = false;
if (dataItem.children[k].name.toLowerCase().indexOf(name.toLowerCase()) != -1){
found = true;
}
if (found){
if (row.element){
domStyle.set(row.element, "display", "block");
}
if (parentRow.element){
domStyle.set(parentRow.element, "display", "block");
}
} else {
childrenHiddenCount++;
// programmatically uncheck any hidden item so hidden items
for (var m in grid.dirty){
if (m === dataItem.children[k].id && grid.dirty[m].selected){
grid.dirty[m].selected = false;
}
}
if (row.element){
domStyle.set(row.element, "display", "none");
}
}
}
// if all of the children were hidden, hide the parent too
if (childrenLength === childrenHiddenCount){
domStyle.set(parentRow.element, "display", "none");
}
}
} catch (err){
console.info("error: ", err);
}
}
I can't seem to get a handle on my list of sortables. They are a list of list elements, each with a
form inside, which I need to get the values from.
Sortables.implement({
serialize: function(){
var serial = [];
this.list.getChildren().each(function(el, i){
serial[i] = el.getProperty('id');
}, this);
return serial;
}
});
var sort = new Sortables('.teams', {
handle: '.drag-handle',
clone: true,
onStart: function(el) {
el.fade('hide');
},
onComplete: function(el) {
//go go gadget go
order = this.serialize();
alert(order);
for(var i=0; i<order.length;i++) {
if (order[i]) {
//alert(order[i].substr(5, order[i].length));
}
}
}
});
the sortables list is then added to a list in a loop with sort.addItems(li); . But when I try to get the sortables outside of the sortables onComplete declaration, js says this.list is undefined.
Approaching the problem from another angle:
Trying to loop through the DOM gives me equally bizarre results. Here are the firebug console results for some code:
var a = document.getElementById('teams').childNodes;
var b = document.getElementById('teams').childNodes.length;
try {
console.log('myVar: ', a);
console.log('myVar.length: ', b);
} catch(e) {
alert("error logging");
}
Hardcoding one li element into the HTML (rather than being injected via JS) changes length == 1, and allows me to access that single element, leading me to believe that accessing injected elements via the DOM is the problem (for this method)
Trying to get the objects with document.getElementById('teams').childNodes[i] returns undefined.
thank you for any help!
not sure why this would fail, i tried it in several ways and it all works
http://www.jsfiddle.net/M7zLG/ test case along with html markup
here is the source that works for local refernece, using the native built-in .serialize method as well as a custom one that walks the dom and gets a custom attribute rel, which can be your DB IDs in their new order (I tend to do that)
var order = []; // global
var sort = new Sortables('.teams', {
handle: '.drag-handle',
clone: true,
onStart: function(el) {
el.fade('hide');
},
onComplete: function(el) {
//go go gadget go
order = this.serialize();
}
});
var mySerialize = function(parentEl) {
var myIds = [];
parentEl.getElements("li").each(function(el) {
myIds.push(el.get("rel"));
});
return myIds;
};
$("saveorder").addEvents({
click: function() {
console.log(sort.serialize());
console.log(order);
console.log(mySerialize($("teams")));
}
});