how to wait for loading data into the store - javascript

There are menu button ("clients"), tree panel with clients list (sorted by name) and viewer with selected client details. There is also selectionchange action..
My task - on button click switch to client view and select and load details for first client every time button has been clicked. My problem - store is not loaded, how waiting until ext js will autoload data to the store?
my controller code:
me.control({
'#nav-client': {
click: me.onNavClientClick
},
...
'clientlist': {
// load: me.selectClient,
selectionchange: me.showClient
}
});
onNavClientClick: function(view, records) {
var me = this,
content = Ext.getCmp("app-content");
content.removeAll();
content.insert(0, [{xtype: 'clientcomplex'}]);
var first = me.getClientsStore().first();
if (first) {
Ext.getCmp("clientList").getSelectionModel().select(me.getClientsListStore().getNodeById(first.get('clientId')));
}
},
...
Two main questions:
is it good solution in my case? (to select first client in tree panel)
var first = me.getClientsStore().first();
// i use another store to get first record because of i dont know how to get first record (on root level) in TreeStore
...
Ext.getCmp("clientList").getSelectionModel().select(me.getClientsListStore().getNodeById(first.get('clientId')));
i know this code works ok in case of "load: me.selectClient," (but only once),
if i place this code on button click - i see error
Uncaught TypeError: Cannot read property 'id' of undefined
because of me.getClientsListStore() is not loaded.. so how to check loading status of this store and wait some until this store will be completely autoloaded?..
Thank you!

You can listen the store 'load' event. Like this:
...
onNavClientClick: function(view, records) {
var me = this;
// if the store isn't loaded, call load method and defer the 'client view' creation
if (me.getClientsStore.getCount() <= 0) {
me.getClientsStore.on('load', me.onClientsStoreLoad, me, { single : true});
me.getClientsStore.load();
}
else {
me.onClientsStoreLoad();
}
},
onClientsStoreLoad : function () {
var me = this,
content = Ext.getCmp("app-content");
content.removeAll();
content.insert(0, [{xtype: 'clientcomplex'}]);
var first = me.getClientsStore().first();
if (first) {
Ext.getCmp("clientList").getSelectionModel().select(me.getClientsListStore().getNodeById(first.get('clientId')));
}
},
...

Related

How to make javascript flow wait till an element is completely rendered

test.view.js
timeDBox = new sap.ui.commons.DropdownBox({layoutData: new sap.ui.layout.GridData({linebreak: true}),
change: function(oEvent){
oController.getKeyEqChart();
},
}),
new sap.ui.core.HTML({
content: "<div id=\"chart1\"></div>",
afterRendering: function(e){
console.log("chart1 create"+timeDBox.getValue());
chart1DivReady = true;
oController.getchart();
}
})
test.controller.js
onInit: function() {
var modelDataEvent = {"genericTableModel":[{"xtime":"1"},{"xtime":"2"},{"xtime":"3"},{"xtime":"4"},{"xtime":"5"},{"xtime":"8"},{"xtime":"10"}]}
var oTemplate11 = new sap.ui.core.ListItem({text : "{xtime}", key : "{xtime}"});
timeDBox.setModel(new sap.ui.model.json.JSONModel(modelDataEvent));
timeDBox.bindItems("/genericTableModel", oTemplate11);
timeDBox.getModel().refresh();
this.getchart();
},
getchart: function(){
var jsonObjToSend = {} ;
jsonObjToSend["dialogue"] = "terminal";
jsonObjToSend["cid"] = "key_equipment ";
var srachmap = {} ;
srachmap["xtime"] = timeDBox.getValue();
jsonObjToSend["search"] = srachmap; this.doAjax("/uri/uri",jsonObjToSend).done(this.updateKeyEqChart);
},
updateKeyEqChart: function(modelData) {
var svg = d3.select("#chart1").append("svg")
1) if i call getchart method from onInit, chart1 id is not created when executing this method
2) if i call getchart chart from oController.getchart() at that time timeDBox.getValue() value is not created which is required to get chart data
},
I am using a drop down list in my application which is populated from database.
Following things happen after the drop down gets populated:
Once the drop down gets populated I use the value of the drop down to render a chart by doing another ajax call to the db.
If the drop down is not populated by the time the flow reaches there then later the chart is not rendered but with time the drop down gets rendered as the ajax where I send param from drop down is null as the drop down is not ready.
So how to make the control wait till the drop down is populated and then go the chart call.
I am not 100% sure that I understand your questions right and the code sample being almost unreadable doesn't help.
But I think onInit might not be the lifecycle hook you are looking for.
If it is a one time deal, I would use onAfterRendering:
onAfterRendering: function() {
// Code
}
If this has to be executed everytime you navigate to this page, then I would add onAfterShow/onBeforeShow delegates in the onInit function.
onInit: function () {
view.addEventDelegate({
/**
* use either or in your case
*/
onAfterShow: function (oEvt) {
// If you use a busy dialog, you want to close it here
},
onBeforeShow: function (oEvt) {
}
});
},
Hope this helps.

dojo for content from ajax call

The case:
I use dojo to request a page and load it into a div ( view ).
The problem:
The content that gets loaded into a form contains a dojo form and relevant objects, textbox, etc... how can I controller these widgets? I believe the current way I am working around the issue is sloppy and could be more refined.
Comments are in the code to help explain the issue I have. Please let me know your thoughts.
function (parser, domAttr, util, ready, dom, on, request, domStyle, registry, TextBox) {
//This prepares the doc main html page We are looking for a click of a menu option to load in thats pages pages content
ready(function () {
//Look for click of menu option
on(dom.byId('steps'), "a:click", function(e) {
event.preventDefault();
//Get the div we are going to load the page into
var view = domAttr.get(this, "data-view");
// function that loads the page contents
load_page(view);
});
});
function load_page(view) {
//First I see if this page already has widgets and destroy them
//We do this so users can toggle between menu items
// If we do not we get id already registered
var widgets = dojo.query("[widgetId]", dom.byId('apply-view')).map(dijit.byNode);
dojo.forEach(widgets, function(w){
w.destroyRecursive();
});
//get the html page we are going to user for the menu item
request.post("/apply_steps/"+view, {
data: {
id: 2
}
}).then(
function(response){
//Add the content and parse the page
var parentNode = dom.byId('apply-view');
parentNode.innerHTML = response;
parser.parse(parentNode);
//This is where it is sloppy
//What I would prefer is to load a new js file the controlls the content that was just loaded
//What happens now is I create a traffic director to tell the code what main function to use
controller_director(view);
},
function(error){
util.myAlert(0, 'Page not found', 'system-alert');
});
}
function controller_director(view) {
//based on the view switch the function
switch(view) {
case 'screening_questions':
screening_questions();
break;
}
}
function screening_questions() {
//Now we are controlling the page and its widgets
// How would I get this info into a seperate js file that i would load along with the ajax call??
ready(function () {
on(dom.byId('loginForm'), "submit", function(e) {
event.preventDefault();
var formLogin = registry.byId('loginForm');
authenticate();
});
});
this.authenticate = function() {
var formLogin = registry.byId('loginForm');
if (formLogin.validate()) return;
}
}
});

how do i implement a "load more" button for meteor collection

******* UPDATE ********
I've asked another question using the suggestion below... but using Iron-Router RouteController
call method in Iron-Router RouteController from Template.tmpl.helpers() not working
Basically what I want to do is have a button that will load more records into my collection on the client. I have an unknown number of records in the db, but I only want the latest 500 or so sent on load to the client.
I'm trying to emulate a "continue search on server" functionality. I'm not looking for a pagination solution.
Suggestions?
------- edited to add code ------------
this is in my /server/publications.js file:
Meteor.publish('clients', function( requestOptions ){
check(requestOptions, Object)
var options = _.extend(opts, requestOptions)
return Clients.find(baseQuery, options)
})
and this is in my /lib/router.js file:
Router.route('/clients', {
name : 'clientList',
waitOn : function(){
return Meteor.subscribe('clients', {limit:500})
}
})
basically i want to show the last 500 new clients, but allow the end-user to "load more" or "load all". i'm not sure how to do that reactively with a subscription...
Attach this event handler to the template that hosts your button:
Template.clients.events({
"click .load-more-button": function (event, template) {
template.skipped += 500;
template.subscriptions.push(Meteor.subscribe("client", {
limit: 500,
skip: template.skipped
}));
}
});
Template.clients.created = function () {
this.subscriptions = [];
this.skipped = 0;
};
//Stop the subscriptions when template is destroyed
Template.clients.destroyed: function () {
_.invoke(this.subscriptions, "stop");
};
As long as your client side cursor does not have a limit set, it should work, however it also means that any clients loaded by other templates etc will appear on the list.

Backbone.View.model.on('change:...') trigged only once

I'm doing ajax file upload for post via modal window with preview in post. Every post has it's own model and a view. Modal window is also a separate view, binded to existing DOM element.
When Attach button in post view is clicked, I call .open() from modal view, passing post model to modal view as settings:
POST VIEW:
======================
ModalAttach.open({
postModel : this.model
});
When file in modal view is uploaded, I add server response to passed Post model to render it later in post itself as a preview:
MODAL VIEW:
======================
// file upload success
success: function(data) {
// if it's first call, set []
var imagesUploaded = self.postModel.get('images_uploaded') || [];
// add server response to array
imagesUploaded.push(data);
// rewrite current model array to new array
self.postModel.set({ 'images_uploaded' : imagesUploaded });
}
To render preview in post (before real submitting), I've got a function
POST VIEW:
======================
renderUploadedImages: function () {
var self = this;
this.$uploadedImagesWrapper = this.$('.b-uploaded__images');
if (this.model.get('images_uploaded')) {
this.$uploadedImagesWrapper.empty();
this.model.get('images_uploaded').forEach(function (uploadedImage) {
self.$uploadedImagesWrapper.append(
uploadedImageTemplate({
'source': uploadedImage.source
})
)
});
}
}
And to trigger image render, I bind a listner to track when model.images_uploaded is changed by modal view:
POST VIEW:
======================
initialize: function () {
this.addEvents();
this.renderUploadedImages();
},
addEvents: function () {
var self = this;
this.model.on('change:images_uploaded', function () {
self.renderUploadedImages();
})
},
The problem is renderUploadedImages() in Post view is trigged only once, at first upload. Other changes are not caught (when postModel.get('images_uploaded').length becomes 2,3,etc..). What I am doing wrong?
Thanks.
When you do like this :
var imagesUploaded = self.postModel.get('images_uploaded') || [];
// add server response to array
imagesUploaded.push(data);
// rewrite current model array to new array
self.postModel.set({ 'images_uploaded' : imagesUploaded });
The first time, if you check self.postModel.get('images_uploaded') you will find it undefined, that's why when you set it the event change:images_uploaded is triggered.
But the second time you call the success method you don't change the the model attribute, it's always pointing to the same object (array), you just change the array value.
Here's an example

How to propertly select items which are still loaded using promises?

I have list of item IDs on page load:
var itemIds = [1, 5, 10, 11];
IDs are rendered into list and shown to user. I have function which loads detailed information about item, it returns Promise/A.
function loadInfo(id) { ... }
Loading of info for all items is initiated on page load:
val infos = {};
$.each(itemIds, function(i, id) { infos[id] = loadInfo(id); }
Now the problem itself.
When user clicks on item ID:
if item info is loaded, info must be shown
if item info is not yet loaded, it must be shown when it is loaded
Looks easy:
$('li').click(function() {
var id = $(this).data('item-id');
infos[id].then(function(info) { $('#info').text(info); });
});
But if user cliked on another item before current one is loaded, then I have to cancel handler on current item promise and schedule on new one.
How to properly do it?
I have several working solutions (like maintaining currentItemId variable and checking it in promise handler), but they are ugly. Should I look to reactive programming libraries instead?
Kriomant,
I guess there's a number of ways you could code this. Here's one :
var INFOS = (function(){
var infoCache = {},
promises = {},
fetching = null;
var load = function(id) {
if(!promises[id]) {
promises[id] = $ajax({
//ajax options here
}).done(function(info){
infoCache[id] = info;
delete promises[id];
});
}
return promises[id];
}
var display = function(id, $container) {
if(fetching) {
//cancel display (but not loading) of anything latent.
fetching.reject();
}
if(infoCache[id]) {
//info is already cached, so simply display it.
$container.text(infoCache[id]);
}
else {
fetching = $.Deferred().done(function() {
$container.text(infoCache[id]);
});
load(id).done(fetching.resolve);
}
}
return {
load: load,
display: display
};
})();
As you will see, all the complexity is bundled in the namespace INFOS, which exposes two methods; load and display.
Here's how to call the methods :
$(function() {
itemIds = ["p7", "p8", "p9"];
//preload
$.each(itemIds, function(i, id) { INFOS.load(id); });
//load into cache on first click, then display from cache.
$('li').on('click', function() {
var id = $(this).data('item-id');
INFOS.display(id, $('#info'));
});
});
DEMO (with simulated ajax)
The tricks here are :
to cache the infos, indexed by id
to cache active jqXHR promises, indexed by id
to display info from cache if previously loaded ...
... otherwise, each time info is requested, create a Deferred associated with display of the info, that can be resolved/rejected independently of the corresponding jqXHR.

Categories

Resources