KendoUI undefined Node issue when trying to add to root parent node - javascript

I have seen other questions with the same issue , the data seems the be the issue most of the time.
I did create a jsfiddle http://jsfiddle.net/gwvoqns8/
(always keep in mind that http has to be used, and not https )
that should demonstrate the problem
I want to have whatever is typed into the text box to display as another named node of whatever name...
The code I'm using seems to enforce me to selected an existing parent node and i do not want that.
Its a bit annoying why it is saying "undefined"
$("#addTopLevel").click(function () {
console.log('in this');
if (treeview.select().length) {
console.log('1');
treeview.append({
text: $("#appendNodeText").val()
}, treeview.select());
} else {
//alert("please select tree node");
console.log('2');
}
});

Try this:
var ds = new kendo.data.HierarchicalDataSource({
data: [
{"Id":1,"ReportGroupName":"Standard Reports","ReportGroupNameResID":null,"SortOrder":1},
{"Id":2,"ReportGroupName":"Custom Reports","ReportGroupNameResID":null,"SortOrder":2},
{"Id":3,"ReportGroupName":"Retail Reports","ReportGroupNameResID":null,"SortOrder":3},
{"Id":4,"ReportGroupName":"Admin Reports","ReportGroupNameResID":null,"SortOrder":5},
{"Id":5,"ReportGroupName":"QA Reports","ReportGroupNameResID":null,"SortOrder":4}
]
});
var treeview = $("#treeview").kendoTreeView({
dataSource: ds,
dataTextField: "ReportGroupName",
loadOnDemand: false
}).data("kendoTreeView");
treeview.expand(".k-item");
$("#addTopLevel").click(function(e) {
var selectedNode = treeview.select();
// passing a falsy value as the second append() parameter
// will append the new node to the root group
if (selectedNode.length == 0) {
selectedNode = null;
}
treeview.append({
ReportGroupName: $("#appendNodeText").val()
}, selectedNode);
});

I was noticing that you could just do this
treeview.append({
ReportGroupName: $("#appendNodeText").val()
}, null);
However, OP answer would be better as then you will have the ability to add to children nodes if you wanted to, even though so said you didn't want to.
cheers

Related

How .elements() works in nightwatch?

Considering I have multiple trs I want to pick one and edit value in it by clicking edit button bounded to it.
I'm doing something like this:
browser.elements('css selector', '#someId tr', elements => {
elements.value.forEach(val => {
console.log(val)
}
And I get something like this:
{
'abcd-1234-qwer-0987': 'some id'
},
{
'abcd-1234-qwer-0987': 'some other id'
}
What is exactly 'abcd-1234-qwer-0987', is this session id kind of stuff and does it change?
What is the best way to grab particular element? Because as I guess my approach is wrong: elements.value[1]['abcd-1234-qwer-0987']
When I run browser.elements and log the entries in the elements.value array, I get something like { ELEMENT: '5' }. So, to answer your questions:
What is exactly 'abcd-1234-qwer-0987', is this session id kind of stuff and does it change?
Probably some sort of session ID, but I'm not sure. Whatever it is, you don't need it for what you're doing.
What is the best way to grab particular element?
If I'm trying to select one out of several similar elements, my code ends up looking something like this:
browser.elements('css selector', '#someId', result => {
// index is defined somewhere else
browser.elementIdClick(result.value[index].ELEMENT, () => {
// whatever you want to do after you click the element.
});
});
If this doesn't work for you, can you share what OS and browser you are running on, as well as your nightwatch configuration file?
Its return the elements items are Web Element json objects. that a Web Element ID
https://nightwatchjs.org/api/commands/#elements
1.What is exactly 'abcd-1234-qwer-0987', is this session id kind of stuff and does it change?
yes it will change according to Session
2.what is the best way to grab particular element
refer the below
Using Nightwatch, how do you get the DOM element, and it's attributes from the ELEMENT entity?
browser.elements('css selector', '#someId tr', elements => {
console.log(elements);
elements.value.forEach(element =>{
let key = Object.keys(element)[0];
let ElementIDvalue = element[key];
console.log("key = ", key);
console.log("WebElementIDvalue = ", ElementIDvalue);
})
});
All of the documentation I've found around what you're trying to do says I should be able to use obj.ELEMENT but what they don't say is that it requires setting w3c to false in your nightwatch config.
Example with context:
test_settings: {
default: {
end_session_on_fail: false,
disable_error_log: false,
launch_url: 'http://localhost:3000',
desiredCapabilities : {
browserName : 'chrome',
'goog:chromeOptions' : {
// More info on Chromedriver: https://sites.google.com/a/chromium.org/chromedriver/
//
// w3c:false tells Chromedriver to run using the legacy JSONWire protocol (not required in Chrome 78)
w3c: true,
args: [
'--auto-open-devtools-for-tabs',
//'--no-sandbox',
. . .
Here is an example of how I use it:
.elements('css selector', `${targetNodeSelector} #nodeCard`, nodeContents => {
console.log(nodeContents.value)
nodeContents.value.forEach(nodeContent => {
console.log(nodeContent.ELEMENT)
// browser.elementIdText(nodeContent.ELEMENT, function (result) {
// console.log('\n' + result.value)
// })
})
})
This will display the correct keys/values:
[
{ ELEMENT: '0.944080972569816-108' },
{ ELEMENT: '0.944080972569816-109' },
{ ELEMENT: '0.944080972569816-110' },

Waiting on collection data prior to rendering a subview

I am building what should be a fairly simple project which is heavily based on Ampersand's starter project (when you first run ampersand). My Add page has a <select> element that should to be populated with data from another collection. I have been comparing this view with the Edit page view because I think they are quite similar but I cannot figure it out.
The form subview has a waitFor attribute but I do not know what type of value it is expecting - I know it should be a string - but what does that string represent?
Below you can see that I am trying to fetch the app.brandCollection and set its value to this.model, is this correct? I will need to modify the output and pass through the data to an ampersand-select-view element with the correct formatting; that is my next problem. If anyone has suggestions for that I would also appreciate it.
var PageView = require('./base');
var templates = require('../templates');
var ProjectForm = require('../forms/addProjectForm');
module.exports = PageView.extend({
pageTitle: 'add project',
template: templates.pages.projectAdd,
initialize: function () {
var self = this;
app.brandCollection.fetch({
success : function(collection, resp) {
console.log('SUCCESS: resp', resp);
self.brands = resp;
},
error: function(collection, resp) {
console.log('ERROR: resp', resp, options);
}
});
},
subviews: {
form: {
container: 'form',
waitFor: 'brands',
prepareView: function (el) {
return new ProjectForm({
el: el,
submitCallback: function (data) {
app.projectCollection.create(data, {
wait: true,
success: function () {
app.navigate('/');
app.projectCollection.fetch();
}
});
}
});
}
}
}
});
This is only the add page view but I think that is all that's needed.
The form subview has a waitFor attribute but I do not know what type of value it is expecting - I know it should be a string - but what does that string represent?
This string represents path in a current object with fixed this context. In your example you've waitFor: 'brands' which is nothing more than PageView.brands here, as PageView is this context. If you'd have model.some.attribute, then it'd mean that this string represents PageView.model.some.attribute. It's just convenient way to traverse through objects.
There's to few informations to answer your latter question. In what form you retrieve your data? What do you want to do with it later on?
It'd be much quicker if you could ping us on https://gitter.im/AmpersandJS/AmpersandJS :)

Route's Model Hook with Ember Data "filter" not loading dependent computed property

Hopefully you can help me! :)
My issue is that I have a Route that looks like this which I'm expecting to populate a list of items... i.e. "only the tagged ones, please", but it doesn't:
App.TaggedItemsListRoute = App.ItemsRoute.extend({
model: function() {
var store = this.get("store");
var storePromise = store.find("item", { has_tags: true });
var filtered = store.filter("item", function(item) {
return item.get("hasTags");
});
return storePromise.then(function(response) {
return filtered;
});
}
});
Now... that just plain doesn't work because "hasTags" returns false because it relies on "tags" which returns a ManyArray which is temporarily empty beacuse it hasn't resolved yet (see models below). This seems crappy to me. It's saying "Hey I've gone none in me!" but what I want it to be saying is "please recalculate me later" and the filter is looking for a boolean, but what I want to pass it is "hey, don't resolve the filter until all hasTags have resolved" or at least to recompute the ManyArray that it passes.
If I just pass back a promise as the return value for the filter then it sort of works...
return item.get("tags").then(function(tags){ return item.get("hasTags"); });
Except that it's actually not, beacuse filter is getting a Promise, but it's not aware of promises, apparently, so when it's looking for a boolean it gets a promise which it evaluates as true, and then it pretty much shows all the items in the list. That's not a problem until I go to a different route for items which has, say, all the items on it, then come back... and BAM it's got all the items in it... hm....
The following is how I've "gotten around" it temporarily ... ie it's still buggy, but I can live with it...
App.TaggedItemsListRoute = App.ItemsRoute.extend({
model: function() {
var store = this.get("store");
var storePromise = store.find("item", { has_tags: true });
var filtered = store.filter("item", function(item) {
var tags = item.get("tags");
if tags.get("isFulfilled") {
return item.get("hasTags");
} else {
return tags.then(function() {
return item.get("hasTags");
});
}
});
return storePromise.then(function(response) {
return filtered;
});
}
});
I think the only way to really get around this at this stage would be to use RSVP.all... any thoughts?
Actually one thing I haven't tried which I might go try now is to use setupController to do the filtering. The only trouble there would be that ALL the items would get loaded inot the list and then visually "jump back" to a filtered state after about 1 second. Painful!
Models
My Ember App (Ember 1.5.1) has two models (Ember Data beta7): Item and Tag. Item hasMany Tags.
App.Item = DS.Model.extend({
tags: DS.hasMany("tag", inverse: "item", async: true),
hasTags: function() {
return !Em.isEmpty(this.get("tags"));
}.property("tags")
});
App.Tag = DS.Model.extend(
item: DS.belongsTo("item", inverse: "tags"),
hasItem: function() {
return !Em.isEmpty(this.get("item"))
}.property("item")
);
If I change the model to the following, it actually does print something to the logs when I go to the route above, so it is fulfilling the promise.
App.Item = DS.Model.extend({
tags: DS.hasMany("tag", inverse: "item", async: true),
hasTags: function() {
this.get("tags").then(function(tags) {
console.log("The tags are loding if this is printed");
});
return !Em.isEmpty(this.get("tags"));
}.property("tags")
});
This is a spin off question from Ember Data hasMany async observed property "simple" issue because I didn't really explain my quesiton well enough and was actually asking the wrong question. I originally thought I could modify my model "hasTags" property to behave correctly in the context of my Route but I now don't think that will work properly...
This seems like a perfectly good candidate for RSVP.all. BTW if you want a rundown on RSVP I gave a talk on it a few weeks back (don't pay too much attention too it, pizza came halfway through and I got hungry, http://www.youtube.com/watch?v=8WXgm4_V85E ). Regardless, your filter obviously depends on the tag collection promises being resolved, before it should be executed. So, it would be appropriate to wait for those to resolve before executing the filter.
App.TaggedItemsListRoute = App.ItemsRoute.extend({
model: function() {
var store = this.get("store");
return store.find("item", { has_tags: true }).then(function(items){
var tagPromises = items.getEach('tags');
return Ember.RSVP.all(tagPromises).then(function(tagCollections){
// at this point all tags have been received
// build your filter, and resolve that
return store.filter("item", function(item) {
return item.get("hasTags");
});
});
});
}
});
Example using a similar idea with colors (I only show it if the relationship has 3 associated colors)
http://emberjs.jsbin.com/OxIDiVU/454/edit
On a separate note, if you felt like you wanted this hook to resolve immediately, and populate magically after, you could cheat and return an array, then populate the array once the results have come back from the server, allowing your app to seem like it's reacting super quick (by drawing something on the page, then magically filling in as the results come pouring in).
App.TaggedItemsListRoute = App.ItemsRoute.extend({
model: function() {
var store = this.get("store"),
quickResults = [];
store.find("item", { has_tags: true }).then(function(items){
var tagPromises = items.getEach('tags');
return Ember.RSVP.all(tagPromises).then(function(tagCollections){
// at this point all tags have been received
// build your filter, and resolve that
return store.filter("item", function(item) {
return item.get("hasTags");
});
});
}).then(function(filterResults){
filterResults.forEach(function(item){
quickResults.pushObject(item);
});
});
return quickResults;
}
});
Example of quick results, returns immediately (I only show it if the relationship has 3 associated colors)
http://emberjs.jsbin.com/OxIDiVU/455/edit

Ember Data hasMany async observed property "simple" issue

Hopefully you can help me!
My Ember App (Ember 1.5.1) has two models (Ember Data beta7): Item and Tag. Item hasMany Tags.
I also have a computed property on tags which doesn't update. The computed property is a simple check to see if there are any tags (ie not empty). I've tried various things. I got as far as arrayComputed and then stopped. It should be reasonably trivial to check if an async related model has a count higher than 0! I've tried "tags.[]", "tags.#each", "tags.#each.status", "tags.#each.isLoaded", "tags.length" and various other things.
The computed property on the belongsTo works fine.
App.Item = DS.Model.extend({
tags: DS.hasMany("tag", inverse: "item", async: true),
hasTags: function() {
return !Em.isEmpty(this.get("tags"));
}.property("tags")
});
App.Tag = DS.Model.extend(
item: DS.belongsTo("item", inverse: "tags"),
hasItem: function() {
return !Em.isEmpty(this.get('))
}.property("item")
);
If I change it to read like this, then the log gets a line printed in it, so the promise is actually fulfilling and loading. I just don't know what to put on the computed property to make it reload when the promise has fulfilled. I feel like I'm missing something super obvious:
App.Item = DS.Model.extend({
tags: DS.hasMany("tag", inverse: "item", async: true),
hasTags: function() {
this.get("tags").then(function(tags) {
console.log("The tags are loding if this is printed");
});
return !Em.isEmpty(this.get("tags"));
}.property("tags")
});
[ edit ] 7 May 2014
Okay so I didn't fully explain the question properly the first go around I guess because I didn't fully understand what was wrong... I've continued the quesiton in the following stack overflow issue: Route's Model Hook with Ember Data "filter" not loading dependent computed property
I believe what you are looking for is this:
App.Item = DS.Model.extend({
tags: DS.hasMany("tag", inverse: "item", async: true),
hasTags: function() {
this.get("tags").then(function(tags) {
console.log("The tags are loding if this is printed");
});
return !Em.isEmpty(this.get("tags"));
}.property("tags.#each")
});
Because tags is an array, you want to be notified when tags are added or removed. the '.#each' will make it update when this happens.
Okay hopefully someone has a better answer than this, but this is how I've "gotten around it" for now, in my routes (I feel like this is an absolutely ridiculous way to do it), by adjusting the thing that relies on "hasTags" rather than adjusting hasTags itself.
Note I'm not even sure if I "fixed up" "hasTags" in Item whether or not it would trigger the filtered reference below to update...?
I think perhaps we need filter to be promise-aware in its block (ie so you can use properties to filter that are promises and it'll do the right thing):
App.TaggedItemsListRoute = App.ItemsRoute.extend({
model: function() {
var store = this.get("store");
var storePromise = store.find("item", { has_tags: true });
var filtered = store.filter("item", function(item) {
var tags = item.get("tags");
if tags.get("isFulfilled") {
return item.get("hasTags");
} else {
return tags.then(function() {
return item.get("hasTags");
});
}
});
return storePromise.then(function(response) {
return filtered;
});
}
});

Meteor method reactivity doesn't work

I'm not experienced in Javascript but I've read a ton of articles about Meteor reactivity but still can't figure out why it is not working in my case.
When a new product is added, I want to be recalculated total cost and use it in the totalCost helper so it's almost real time visible in the browser.
Can someone please take a look at my code and try to figure out some logic error? Everything except the reactivity is working on my computer.
I have got this method in /models/Product.js :
Meteor.methods({
totalProductCost: function() {
var pipeline = [
{$match: {owner: Meteor.userId()}},
{$group: {_id: null, cost: {$sum: "$cost"}}}
];
var data = Products.aggregate(pipeline)["0"].cost;
return (data === undefined) ? 0 : data;
}
});
Then I've got layout.js in client folder:
if (Meteor.isClient) {
var handle = Meteor.subscribe("Products", Meteor.userId());
ProductManager = {
_productItems: null,
_dep: new Tracker.Dependency(),
getProducts: function () {
this._dep.depend();
return this._productItems;
},
setProducts: function (value) {
if (value !== this._productItems) {
this._productItems = value;
this._dep.changed();
}
},
getTotalCost: function () {
return ReactiveMethod.call('totalProductCost');
}
}
// TRACKER
Tracker.autorun(function () {
if (handle.ready()) {
ProductManager.setProducts(Products.find().fetch());
}
});
// HELPERS
Template.boxOverview.helpers({
"totalCost" : function () {
return ProductManager.getTotalCost();
},
});
}
It seems that you used a collection.aggregate in a method. If you need reactivity, you need to use a publication rather than a method (or you need to call the method each time you want to refresh). However, if you use your aggregation inside your publication (I assume you use a package for it) you will loose reactivity as well.
What I would advise you is to use a publication without aggregate function. You calculate your product cost by creating a new field and adding it to your cursor. Once, you do that, if you want to keep reactivity, it is necessary to use to use cursor.observeChanges() or just cursor.observe().
Have a look at this example:
var self = this;
// Modify the document we are sending to the client.
function filter(doc) {
var length = doc.item.length;
// White list the fields you want to publish.
var docToPublish = _.pick(doc, [
'someOtherField'
]);
// Add your custom fields.
docToPublish.itemLength = length;
return docToPublish;
}
var handle = myCollection.find({}, {fields: {item:1, someOtherField:1}})
// Use observe since it gives us the the old and new document when something is changing.
// If this becomes a performance issue then consider using observeChanges,
// but its usually a lot simpler to use observe in cases like this.
.observe({
added: function(doc) {
self.added("myCollection", doc._id, filter(doc));
},
changed: function(newDocument, oldDocument)
// When the item count is changing, send update to client.
if (newDocument.item.length !== oldDocument.item.length)
self.changed("myCollection", newDocument._id, filter(newDocument));
},
removed: function(doc) {
self.removed("myCollection", doc._id);
});
self.ready();
self.onStop(function () {
handle.stop();
});
This is taken from here.

Categories

Resources