How to avoid showing loading text in Ext.form.ComboBox? - javascript

I use Ext.form.ComboBox in very similar way as in this example:
http://extjs.com/deploy/dev/examples/form/forum-search.html
What annoys me is that when the ajax call is in progress it shows loading text and I cannot see any results from before.
Eg I input 'test' -> it shows result -> I add 'e' (search string is 'teste') -> result dissapear and loading text is shown, so for a second I cannot see any result and think about if it's not what I'm searching for...
How can I change this to simply not to say anything when 'loading'...

The solution is to override 'onBeforeLoad' method of Ext.form.ComboBox:
Ext.override(Ext.form.ComboBox,
{ onBeforeLoad:
function() {this.selectedIndex = -1;}
});
Please be warned, that this overrides the class method, so all of the ComboBox instances will not have the LoadingText showing. In case you would like to override only one instance - please use plugins (in quite similar way).
You may also look at Ext.LoadingMask to set an appropriate loading mask to aside element if you wish.

If you don't show loading message to user how user will know what is happening? User will notice that its already loading results so may wait to see the results, but if nothing displayed then user wouldn't know if its bringing new data or not.

You may monit the expand event of the combobox and set picker loading to false.
// in the controller
init: function() {
this.control({
"form combobox[id=fieldId]": {
expand: function(combobox) {
combobox.getPicker().setLoading(false);
}
}
});
}

Related

Using FullCalendar, how to add information to EventObject when eventReceive?

I've started discovering and using FullCalendar but I'm stuck with it.
What I want to do is a ResourceTimeline in Month view, with external event dragging (a left panel).
The subject later would be to have a modal when you drop an event, in order to choose if you want the event to be from 8am to 12pm, or afternoon from 12pm to 6pm.
So first, I'd like to do a simple eventReceive without modal, to see if I can update the event when it's dropped.
But it seems I can't, what do I do wrong ?
From what I can understand, it looks like when you drop an event in month view, the event in the param sent to eventReceive is modified.
eventReceive(info) {
info.event.start = moment(info.event.start).add(8, 'hours').format('YYYY-MM-DD hh:mm:ss');
// var c = confirm('OK = morning, Cancel = aprem');
// if (c) {
// console.log("morning !")
// } else {
// console.log("afternoon !")
// }
}
Events are very basic because I wanted to complete them whenever I drop them into the calendar
new Draggable(listofEvents, {
itemSelector: '.draggable',
eventData(event) {
return {
title: event.innerText,
activite: event.dataset.activite,
allDayDefault: false,
}
},
})
I even tried to force allDayDefault to false but it doesn't change a thing...
Here is the codepen of the project in its current state : https://codepen.io/nurovek/pen/zYYWGyX?editors=1000
Sorry if my post lacks information, I'm not used to ask questions on SO. If it's lacking, I'll try to be more explicit if you ask me, of course !
As per the documentation, an event's public properties (such as "start", "end", title" etc) are read-only. Therefore to alter a property after the event is created you must run one of the "set" methods.
So your idea will work if you use the setDates method:
eventReceive(info) {
info.event.setDates(moment(info.event.start).add(8, 'hours').toDate(), info.event.end, { "allDay": false } )
console.log(info.event);
}
Demo: https://codepen.io/ADyson82/pen/dyymawy?editors=1000
P.S. You might notice I also made a few other little changes to your CodePen, mainly to correct all the links to CSS and JS files, since it was generating all sorts of console errors. These errors were because links were wrong or simply referred to something non-existent, and for some reason you were also using files from two different versions of fullCalendar (4.3.0 and 4.3.1), which is never a good idea if you want to ensure full compatibility.

ExtJS 4 grid and some problems with mask

I have a not too big grid (30x20) with numbers in cells. I have to display all, calculate them in different ways (by columns, rows, some cells, etc.) and write values to some cells. This data is also written and read from db table fields. Everything is working, excluding simple (theoretically) mask tools.
In time of e.g. writing data to the field in the table I try to start mask and close it on finish. I used such a “masks” very often but only in this situation I have a problem and can’t solve it.
I prepare this mask the following way:
msk = new Ext.LoadMask(Ext.getBody(), { msg: "data loading ..." });
msk.show();
[writing data loops]
msk.hide();
msk.destroy();
I also tried to use grid obiect in place of Ext.getBody(), but without result.
I found also that the program behaves in a special way – loops which I use to write data to the table field are "omitted" by this mask, and it looks like loops are working in the background (asynchronously).
Would you be so kind as to suggest something?
No, no, no, sorry guys but my description isn’t very precise. It isn’t problem of loading or writing data to the database. Let’s say stores are in the memory but my problem is to calculate something and write into the grid. Just to see this values on the screen. Let me use my example once again:
msk = new Ext.LoadMask(Ext.getBody(), { msg: "data loading ..." });
msk.show();
Ext.each(dataX.getRange(), function (X) {
Ext.each(dataY.getRange(), function (Y) {
…
X.set('aaa', 10);
…
}
msk.hide();
msk.destroy();
And in such a situation this mask isn’t visible or is too fast to see it.
In the mean time I find (I think) a good description of my problem but still can’t find a solution for me. When I use e.g. alert() function I see this mask, when I use delay anyway, mask is too fast. Explanation is the following:
The reason for that is quite simple - JS is single threaded. If you modify DOM (for example by turning mask on) the actual change is made immediately after current execution path is finished. Because you turn mask on in beginning of some time-consuming task, browser waits with DOM changes until it finishes. Because you turn mask off at the end of method, it might not show at all. Solution is simple - invoke store rebuild after some delay.*
I have no idea how is your code looks in general but this is some tip that you could actually use.
First of all loading operations are asynchronously so you need to make that mask show and then somehow destroy when data are loaded.
First of all check if in your store configuration you have autoLoad: false
If yes then we can make next step:
Since Extjs is strongly about MVC design pattern you should have your controller somewhere in your project.
I suppose you are loading your data on afterrender or on button click event so we can make this:
In function for example loadImportantData
loadImportantData: function(){
var controller = this;
var store = controller.getStore('YourStore'); //or Ext.getStore('YourStore'); depends on your configuration in controller
var myMask = new Ext.LoadMask(Ext.getBody(), {msg:"Please wait..."});
myMask.show();
store.load({
callback: function (records, operation, success) {
//this callback is fired when your store load all data.
//then hide mask.
myMask.hide();
}
});
}
When data is loaded your mask will disappear.
If you have a reference to the grid, you can simply call grid.setLoading(true) to display a loading mask over the grid at any time.

Dynamically loading a database based on user text input

I have an autocomplete widget which needs to return options from a database of objects.
On doing so, once the user selects an item the widget will populate other hidden textfields with values from the particular object they chose. - All of this works and has been used on previous projects
However this particular database is far too big (44k+ objects, filesize is several mb and has taken far too long to load in practice) so we've tried various ways of splitting it up. So far the best has been by first letter of the object label.
As a result I'm trying to create a function which tracks the users input into a textfield and returns the first letter. This is then used to AJAX a file of that name (e.g. a.js).
That said I've never had much luck trying to track user input at this level and normally find that it takes a couple keystrokes for everything to get working when I'm trying to get it done on the first keystroke. Does anyone have any advice on a better way of going about this objective? Or why the process doesn't work straight away?
Here is my current non-working code to track the user input - it's used on page load:
function startupp(){
console.log("starting");
$("#_Q0_Q0_Q0").on("keyup", function(){
console.log("further starting!");
if($("#_Q0_Q0_Q0").val().length == 1){
console.log("more starting");
countryChange(($("#_Q0_Q0_Q0").val()[0]).toUpperCase());
}
else{
console.log("over or under");
}
});
}
And an example of the data (dummy values):
tags=[
{
label:"label",
code:"1",
refnum:"555555",
la:"888",
DCSF:"4444",
type:"Not applicable",
status:"Open",
UR:"1",
gRegion:"North West"
},
....
];
edit: fixes applied:
Changed startupp from .change(function) to .on("keyup", function) - keydown could also be used, this is personal preference for me.
Changed the autocomplete settings to have minLength: 4, - as the data starts loading from the first letter this gives it the few extra split ms to load the data before offering options and also cuts down how much data needs to be shown (helps for a couple of specific instances).
Changed how the source is gathered by changing the autocomplete setting to the following:
source: function(request, response) {
var results = $.ui.autocomplete.filter(tags, request.term);
response(results.slice(0, 20));
},
where tags is the array with the data.
all seems to be working now.
You should bind to keydown event:
function startupp(){
console.log("starting");
$("#_Q0_Q0_Q0").keydown(function(){
console.log("further starting!");
if($(this).length() == 1){
console.log("more starting");
countryChange(($(this).val()[0]).toUpperCase());
}
else{
console.log("over or under");
}
});
}

storing a variable in localStorage is too slow

I have two jQuery mobile pages (#list and #show). There are several items on the #list page with different IDs. If I click on item no.5, the ID no5 will be stored in localStorage and I will be redirected to page #show
Now the problem:
Storing the ID in localStorage works, but the next page shows me not the item no.5, but it shows me an old item, that was in the localStorage before.
script from page #list
localStorage.setItem("garageID", $(this).attr('id'));
window.location.replace("#show");
I encountered this problem too (and not on a mobile : on Chromium/linux).
As there doesn't seem to be a callback based API, I "fixed" it with a timeout which "prevents" the page to be closed before the setItem action is done :
localStorage.setItem(name, value);
setTimeout(function(){
// change location
}, 50);
A timeout of 0 might be enough but as I didn't find any specification (it's probably in the realm of bugs) and the problem isn't consistently reproduced I didn't take any chance. If you want you might test in a loop :
function setLocalStorageAndLeave(name, value, newLocation){
value = value.toString(); // to prevent infinite loops
localStorage.setItem(name, value);
(function one(){
if (localStorage.getItem(name) === value) {
window.location = newLocation;
} else {
setTimeout(one, 30);
}
})();
}
But I don't see how the fact that localStorage.getItem returns the right value would guarantee it's really written in a permanent way as there's no specification of the interruptable behavior, I don't know if the following part of the spec can be legitimately interpreted as meaning the browser is allowed to forget about dumping on disk when it leaves the page :
This specification does not require that the above methods wait until
the data has been physically written to disk. Only consistency in what
different scripts accessing the same underlying list of key/value
pairs see is required.
In your precise case, a solution might be to simply scroll to the element with that given name to avoid changing page.
Note on the presumed bug :
I didn't find nor fill any bug report as I find it hard to reproduce. In the cases I observed on Chromium/linux it happened with the delete operation.
Disclaimer: This solution isn't official and only tested for demo, not for production.
You can pass data between pages using $.mobile.changePage("target", { data: "anything" });. However, it only works when target is a URL (aka single page model).
Nevertheless, you still can pass data between pages - even if you're using Multi-page model - but you need to retrieve it manually.
When page is changed, it goes through several stages, one of them is pagebeforechange. That event carries two objects event and data. The latter object holds all details related to the page you're moving from and the page you're going to.
Since $.mobile.changePage() would ignore passed parameters on Multi-page model, you need to push your own property into data.options object through $.mobile.changePage("#", { options }) and then retrieve it when pagebeforechange is triggered. This way you won't need localstorage nor will you need callbacks or setTimeout.
Step one:
Pass data upon changing page. Use a unique property in order not to conflict with jQM ones. I have used stuff.
/* jQM <= v1.3.2 */
$.mobile.changePage("#page", { stuff: "id-123" });
/* jQM >= v1.4.0 */
$.mobile.pageContainer.pagecontainer("change", "#page", { stuff: "id-123" });
Step two:
Retrieve data when pagebeforechange is triggered on the page you're moving to, in your case #show.
$(document).on("pagebeforechange", function (event, data) {
/* check if page to be shown is #show */
if (data.toPage[0].id == "show") {
/* retrieve .stuff from data.options object */
var stuff = data.options.stuff;
/* returns id-123 */
console.log(stuff);
}
});
Demo

extjs4 mvc event debugging inconsistent results

I have a grid.Panel inside of a viewport that is binded to a store. Once the grid (or store) is loaded, I would like to look at a value in the first row (or any row), and if it's false, hide a column in the grid. I've tried many different events, but here's an example in my controller:
Ext.define('HelperBatchForm.controller.BatchController', {
extend: 'Ext.app.Controller',
stores: [
'Batches'
],
models: [
'Batch'
],
views: [
'batch.BatchGrid',
'batch.BatchEdit'
],
init: function () {
this.control({
'batchgrid': {
itemdblclick: this.editBatch
,viewready: this.onGridLoad
}
});
},
onGridLoad: function(grid){
stop;
},
"Stop" throws an error and opens the debugger in my IE browser. On the browser itself I can see the grid, and the rows, fully rendered. In the debugger, I can look at grid.store.data.items[0] and see the first row. So it seems that everything is well, and I should be able to put a condition in the function based on that data which hides the grid. But that doesn't work - here is where things start to get weird.
If I replace "stop;" with "debugger;", and reload, this time we get the visual studio debugger. But now, in the IE screen, I can only see the grid headers, and none of the data. And grid.store.data.items is an empty array. The instant I resume, I see the full grid.
But that's not all. If my function is:
onGridLoad: function (grid) {
alert('onGridLoad');
debugger;
},
Now, with the visual studio debugger loaded, I can see the full grid and data in IE. And grid.store.data.items[0] gives me the first row. If I replace "debugger" with my conditional code, it works! In other words, I have code that doesn't work, but suddenly starts working if I throw an alert() before it.
To summarize, the code below will hide the column:
onGridLoad: function (grid) {
alert('onGridLoad');
if (grid.store.findExact('is_rcm', false) >= 0) {
grid.columns[6].hide();
}
},
But if the alert is commented out, it will not hide the column.
Any ideas or explanations to why this might be would be greatly appreciated.
My guess the issue here is related to async loading of the store. You are probably seeing a race condition of a split second between the view is ready but the store is not yet populated. Just like in quantum physics the observation of the event is changing its outcome :)
My suggestion is to put a load listener on the store instead and inject your processing at that point.
I think that #dbrin is correct in assuming the data in the store is not yet loaded. But doing the processing on store load might also be problematic, when store load time is very fast, and the view is not yet ready. The following should work when the data is ready either after or before the view:
viewready: function(grid){
grid.getView().on({
refresh: {
fn: function(){
if (grid.store.findExact('is_rcm', false) >= 0) {
grid.columns[6].hide();
}
},
single: true
}
});
}
And here is a fiddle, where you can set the store load delay to test for different load times.

Categories