I see multiple loading masks when two Ajax requests are called parellely - extjs

In my sencha touch app whenever I call an Ajax request I set a loading mask on the screen until some response is sent back but lets say I have more than one Ajax request executing at the same time, I see multiple loading masks. How do I stop this from happening. I tried to put a check like
if(Ext.Viewport.getMasked()){
//bypass
}
else {
Ext.Viewport.setMasked({
xtype: 'loadmask'
});
}
But this not seem to work and when request is completed I do this
Ext.Viewport.unmask();
But my problem is that I see two masks if e.g. two requests are running parallely. Is there is a way to prevent this from happening.
I am using Sencha touch 2.3.0

Your problem might be that you are doing Ext.Viewport.getMasked instead of Ext.Viewport.getMasked(). Regardless, if you are setting multiple loadmasks on the same component (in this case, Viewport) the new one will replace the older. Most likely you are setting these masks on different components, which is why you are seeing more than one.
Here is a link to a Sencha Fiddle showing how Viewport loadmasks replace. If you are still having issues, please share some code.

Related

Delay generating directive until after page is ready and responsive

I'm working on a single-page app where some parts are really slow. They're slow because I'm displaying 400 complex things in a repeater for the user to scroll through. Each thing is generated by a fairly complex directive that does a ton of data binding and expression evaluation, adds one or two click handlers, and displays a couple of images. In some cases, I also need a grayscale CSS filter on those images, but that really seems way too slow.
I have of course already turned most of my data binding into one-time data binding, but simply generating the 400 things for the first time is still slow. It's initially hidden through ng-if, which speeds it up when I'm not showing it, but once I do need to show it, everything waits 10 seconds for that to happen. I would like to load it in advance, but using ng-show instead of ng-if means the loading of the entire app has to wait for this.
What I would like, is to load the rest of the app, and then, while we wait for user input, start creating these 400 things so they're ready once I need to show them. I don't want the user to notice how slow this is.
Problem is, I have no idea how to do this. Any ideas?
Edit: Having thought about this (and discussed this with my wife), I'm seeing two options (that I conceptually understand, at least):
The easy, quick, boring and cowardly solution is to simply not show the 400 things at the same time, but cut them in pieces and show 40 at a time. That should make it a lot quicker, but also less nice, as the user needs to click around to access all the data.
The interesting solution is to write a new ng-repeat that generates the 400 transcluded copies of the template each in their own asynchronous event, so they don't block user interaction. I really like this idea, but there's one big downside: it's an ambitious idea with deep Angular magic, and I don't have much time available.
OK, not seeing your code structure, through Q&A, I'm trying to get clarification. If I understand you correctly, I believe the solution is to process your images asynchronously and remove reliance of creating/processing them on the fly when the view is visible (i.e. via clicking on a button/tab to 'show' the array 'view' and thus triggering the ng-repeat). BTW, this solution assumes the delays are because the images are being processed rather than because they are being shown.
METHOD 1 (less preferred)
To do this, it's best to create an 'ImageDataService' service, where it get's kicked off at application start, and proceeds with building this array and taking whatever time it needs asynchronously without caring what view is showing or not. This service will be injected into the proper view or directive controller--perhaps where the current ng-repeat scope is.
Meanwhile, you also need to change the directives inside your ng-repeat to get the pre-built data from the array provided by ImageDataService rather than actually doing the calculation at view time. If the data for that directive is not ready, the directive will show something like 'loading...' otherwise, the directive will simply show the prebuilt images. This way, it doesn't matter when ng-repeat is triggered (i.e. its view is showing), because it will just show what are processed and ready at that point and the display the rest as 'loading...'.
METHOD 2 (I prefer this)
Alternatively, and maybe better, you can forego creating a pre-processed array in a service as in METHOD 1 and instead modify your directives to process their data asynchronously by invoking a service method that returns an asynchronous promise like this:
(code inside a controller)
var promise = ImageDataService.processImage(directiveData);
promise.then(function() {...set the directive image attributes..})
Needless to say, the ImageDataService.processImage() method needs to return a promise when it is done processing the data. The directive, as usual, will show 'loading...' until then. Also, although ImageDataService no longer needs to pre-populate its array mentioned in METHOD 1, it might be a good idea to save the processed images to a similar array anyway to serve as cache and not reprocess them needlessly. NOTE, in this case you don't need to have processImage() inside a service--but it is really good 'separation of concerns' practice to reserve the work of asynchronous data processing (ajax, etc) within a service which can be injected app-wide rather than within a controller.
Either of these 2 general tacks should work.

Extend Store class to always execute a function after load on ExtJS

I am working on a project where we were asked to "patch" (they don't want a lot of time spent on development as they soon will replace the system) a system implemented under ExtJS 4.1.0.
That system is used under a very slow and non-stable network connection. So sometimes the stores don't get the expected data.
First two things that come to my mind as patches are:
1. Every time a store is loaded for the first time, wait 5 seconds and try again. Most times, a page refresh fix the problem of stores not loading.
Somehow, check detect that no data was received after loading a store and, try to get it again.
This patches should be executed only once to avoid infinite loops or unnecessary recursivity, given that it's ok that some times, it's ok that stores don't get any data back.
I don't like this kind of solutions but it was requested by the client.
This link should help with your question.
One of the posters suggests adding the below in an overrides.js file which is loaded in between the ExtJs source code and your applications code.
Ext.util.Observable.observe(Ext.data.Connection);
Ext.data.Connection.on('requestexception', function(dataconn, response, options){
if (response.responseText != null) {
window.document.body.innerHTML = response.responseText;
}
});
Using this example, on any error instead of echoing the error in the example you could log the error details for debugging later and try to load again. I would suggest adding some additional logic into this so that it will only retry a certain number of times otherwise it could run indefinitely while the browser window is open and more than likely crash the browser and put additional load on your server.
Obviously the root cause of the issue is not the code itself, rather your slow connection. I'd try to address this issue rather than any other.

how to resolve race conditions in webdriver

I have an app that uses a mixture of angular and asp.net. My issue is that the home page is redirected by setting window.location and then the required data and page is requested form the server.
Previously this was not the case and all routing was done via the angular app. However due to requirements the applications routing had to be changed to what it is now.
Now because the application requires a server side request/response (I believe) this is causing a race condition in my tests as I only receive the expected result once in every 5 tests.
At present I am not able to provide code to explain my situation. However, I will be albe to provide some code in a edit later today.
The only code I can provide for now would be the test that is being run. Although I do not believe this would help without the code running the application.
Recent frameworks have this feature where it sets the document.readState of browser to complete and the content is loaded afterwards. Due to this the test may fails as we will be expecting an element to be present.
For such conditions you have to use explicit wait for the element to be present for which you want to take an action after the page is loaded or changed.
Here is an example how we wait for elements in our project (The application is also angularjs, we use Java for webdriver):
In our Webdriver implementation we added:
private WebDriverWait iWait(int timeoutInSeconds) {
return new WebDriverWait(webDriver, timeoutInSeconds);
}
we want to wait for an element to be visible ("Visibility means that the element is not only displayed but also has a height and width that is greater than 0"):
public void waitForElementToAppear(By by, int timeoutInSeconds) {
iWait(timeoutInSeconds).ignoring(StaleElementReferenceException.class).until(ExpectedConditions.visibilityOfElementLocated(by));
}
the ExpectedConditions class provides many other out of the box condition, here are some:
elementToBeClickable
textToBePresentInElement
titleContains
elementSelectionStateToBe
for more, please look at the ExpectedConditions Javadoc
if you need to create your own conditions, you can use ExoectedCondition (no 's') class
ExpectedCondition Javadoc

CakePHP: Caching does not work

I am having the following issues: my cakephp app is not handling the cache thing properly. As suggested by every result in google, I created a function in the model to manually delete the cache:
public function afterSave($created) {
Cache::clear();
clearCache();
}
Unfortunately, this is doing nothing. Doesn't delete anything, and I still have the problem.
In case I have no explained myself properly, I will give an example of what happens:
I go with my browser to a page that shows a list of the last 5 records in my database. Then I go and add another record. I come back to the page that shows the last 5, and the information is not updated. It uses the cache and comes back with outdated info. If I press F5, then he page trully reloads and I see the trully 5 last records.
And that's it, I don't know what to do. The whole app works like crap, because you do something and it never appears unless you refresh the page with F5, which is something of course users are unaware, leading them to think "nothing was added" when it actually was.
Cache::clear() will only clear entries that have expired.
Try Cache::clear(FALSE). Works if you have CakePHP 2.x.
I did this to solve the problem: In the controllers, inside beforefilter function I made a check, if the action is something I disable the cache.
The actions you choose won't have browser cache.
function beforeFilter(){
if ($this->action == 'youraction'){
$this->disableCache();
}
}
Use of caching required lots of thinking, where to use where to not. If your update is frequent, don't use caching there.
We use caching where data rarely change, at that moment it is win-win situation.
Cache::clear($check, $config = 'default')
Destroy all cached values for a cache configuration.
cakephp Caching

Sencha Touch store 'aftersync'-like event

I'm using a ListView with a store/ajax-proxy/json-reader/json-writer. I'd like to set the ListView to loading before I call store.sync(), and remove the loading once the response got back from the server.
Problem is, I don't know where I could hook in my call to be processed once the request is done, as all I'm doing is calling sync().
Store has a beforesync event, what I'd like is something like aftersync. Any ideas how to accomplish that?
By reading the Sencha Touch source code, it turns out that the afterRequest function is called just after the request is finished. This config option can be passed to any Ext.data.Proxy subclass. The two arguments passed are request and success.
Interesting though that it's not present in the API docs.

Resources