I have this search function , which should refresh the page first (clean what was in the page)and then show the results.
What happens is that the page shows the results first and then refreshs the page.
searchForm.addEventListener("submit" , function(event)
{
window.location.reload(); //should do this first
event.preventDefault();
searchedName.innerText = searchBar.value;
changeLogoImage(searchedName);
giveCompanieSymbol(searchedName);
TurnVisible(companyLogo);
TurnVisible(overviewDataContainer);
TurnVisible(separadoresAnalise);
TurnVisible(personaliseParagrafo);
}
)
I can't think of a easy/simple solution to do this without creating another function or separated events. Isn't there an easier way to say to this function :
"First reload the page , then show the results." ?
I thought this is what would happen If I place the reload() in the first line of the function but doesn't seems to be the case.
You can't refresh the page and then make modifications to it, because the environment in which your code was running (along with your code) has been torn down and discarded by the process of reloading the page.
Instead, either:
Modify the page in place rather than refreshing it.
or
Encode the search information in query string parameters and assign teh URL to window.location to load the new page, and read and apply those query string parameters on page load.
or
Use sessionStorage to store them temporarily and then, again, apply them on page load.
#1 is a common approach these days. Given it's search information, #1 is also quite a normal way to do this.
Related
I have the below scenario:
I search for an element in search box. when the element appears (it may take some time), I click on the element which loads a new view. Then I try to click on some button in new view. since it takes some time to load the search result, the new view does not load. Any way I can avoid wait()?
This is what I have:
cy.get('[data-cy="search"][data-component="input_box"]').type('Find me{enter}')
cy.wait(200) // How to avoid this???
cy.get('[data-name="Find me"]').contains('Find me').click()// Should load a new view
cy.get('[data-cy = "filter"]').click() // failing here as new view is not loaded
Any suggestions will be highly appreciated.
Similar one:
describe('Tutorialspoint Test', function () {
// test case
it('Test Case1', function (){
// test step to launch a URL
cy.visit("https://www.tutorialspoint.com/videotutorials/index.php");
// enter test in the edit box
cy.get("#search-strings").type("Java");
// wait for some time
cy.wait(3000); // ---> how to avoid this?
// using jQuery selector to identify only visible elements
// assertion to validate the number of search results
cy.get('.clsHeadQuestion:visible'). should('have.length',19);
});
});
In similar situation you can use cy.route() which grab the network request and wait for it. In your case, the route will grab the n/w req and wait for the "Find me" request to get processed completely so that you can proceed with the next filter action.
Steps:
Open the chrome console, navigate to network tab, filter for XHR request. Now click on the ''Find me'' button in you page. You can see usually a GET request, for example if the request looks as follows, https://example.com.au/v1/api/listview?page=2
Please copy the url from /v1/api/... and add into the url value of cy.route() as below.
note: On click on Find me button, see its a GET or POST request, usually it will be GET request, check if the url has any encoded value, if it has encoded value you have to use decodeURIComponent() and the pass the url inside as follows >> url:decodeURIComponent('**/v1/api/listview?page=2**'),
beforeEach(()=>{
cy.server();
cy.route({
method: 'GET',
url:'**/v1/api/listview?page=2**',
delay: 2000
}).as('getLoadNewView');
})
it('Route waiting for loading the new view for filter action', () => {
cy.get('[data-cy="search"][data-component="input_box"]').type('Find me{enter}')
cy.get('[data-name="Find me"]').contains('Find me').click()// Should load a new view
cy.wait('#getLoadNewView');
cy.get('[data-cy = "filter"]').click();
})
Could you try adding an extra timeout to the get? Something like:
cy.get('[data-name="Find me"]', { timeout: 1000 }).contains('Find me').click()
It's not a perfect solution, but sometimes adding a timeout like that can help.
I would guess that there is some network activity going on on the background after you finish typing in the search bar. I usually wait for the request(s) to be completed and then check UI elements, when I have similar cases.
https://www.cypress.io/blog/2019/12/23/asserting-network-calls-from-cypress-tests/, scroll down to “Waiting for the network call to happen” section.
cy.wait('....') is still there, but this time I wait for something explicit that effects the UI
I have an Angular 4 application in which I need to add the following functionality:
There is a component with a list of objects. When the user double clicks on one of them, the app retrieves from a DB a list of objects and it should scroll to where the object appears.
I'd like to know how I could move to the desired position in the data once that it has been displayed in the browser. Right now, I have the following code:
let objElement = document.querySelector("#object_"+searchItem._objectID);
if (objElement){
objElement.scrollIntoView();
console.log("****** SCROLLING TO OBJECT");
}
The problem is that, the first time that I load the data from the DB, it seems that 'document.querySelector' returns null, as if the HTML wasn't 100% constructed yet, so it doesn't scroll to the position. If I try to locate the element again, it scrolls perfectly (as it doesn't reload the data from the DB).
Is there a "more Angular" way of doing this? I'm trying to find an example like this in the Angular Router documentation but I can't find anything...
EDIT:
To make things clearer, this is the pseudo-code that I run when the user selects an object:
if(selectedObject IS IN currentLoadedObjects) {
scrollTo(selectedObject); // This function runs the code above
}
else { // The object is in a different list, so retrieve it from the DB
ObjectService.getObjectListFromDB(selectedObject)
.subscribe((returnedList) => {
displayObjectList(returnedList); // Basically, this function parses the returned data, which is displayed in the template using an *ngFor loop
scrollTo(selectedObject);
});
}
As you can see, I try to scroll to the object inside the 'subscribe' method, once that I have the data from the database and after I've parsed it. The object list is pretty big, so it takes 1-2 seconds to be displayed in the browser.
Thanks!
I have an ajax call that builds a small graph in a popup window. The html for the link is re-used in many different links for different devices on the page. What happens, is that when you click a graph for the first device, you get that device. You click a button for the second device, you get that device, however, if you keep clicking away, after the third click or so, you suddenly start getting only the first device, over and over. I think my variables are being cached in some odd way, and I don't understand:
the HTML:
<a class="bluebtn graphbutton ingraph" href="http://wasat/cgi-bin/rrdjson.cgi?res=3600&start=-24h&end=now-1h&uid=28.7B2562040000" data-uid="28.7B2562040000" data-name="Laundry Room Freezer"></a>
<a class="bluebtn graphbutton ingraph" href="http://wasat/cgi-bin/rrdjson.cgi?res=3600&start=-24h&end=now-1h&uid=28.F7A962040000" data-uid="28.F7A962040000" data-name="Garage Temp"></a>
The code in question:
$(document).ready(function() {
$('.graphbutton').click(function(e) {
var formURL = $(this).attr("href");
var uid = $(this).data("uid");
var name = $(this).data("name");
e.preventDefault();
$.ajax({
url: formURL,
dataType: "json",
cache: false,
context: this,
success: function(data){
console.log("calling mkgraph with uid "+uid+" name " +name);
make_graph(data.data, uid, name);
},
error: function(ts) {
console.log(ts.responseText); }
});
}); /* clickfunc */
}); /*docready */
What happens:
Click freezer:
"calling mkgraph with uid 28.7B2562040000 name Laundry Room Freezer"
Click Garage:
"calling mkgraph with uid 28.F7A962040000 name Garage Temp"
Click Garage again:
"calling mkgraph with uid 28.7B2562040000 name Laundry Room Freezer"
Some of these links are being manufactured by the make_graph() function. I'm a bit worried that this is the issue, and somehow the ajax thing needs to be re-initialized after doing this?
By request, the relevant code in make_graph() that I think is causing my issue here. Basically, I'm editing the buttons in the css popup on the fly, and I think this is creating a wierd situation where the ajax binding is bound to the old href, and not being updated, even though the link is correct in the produced html. This is consistent with the effect where the binding only gets mangled on the third attempt.
$(".ingraph").each(function() {
this.href = $(this).attr("href").replace(/uid=.*/g, 'uid=' + uid);
this.setAttribute('data-uid' ,uid);
if (devname.length > 0) {
this.setAttribute('data-name', devname);
}
});
EDIT: adding a long answer:
I have multiple buttons on the main page. Each one specifies a "uid" that gets fed to rrdjson.cgi, which takes the uid and finds the data for that device, and returns it as json. When make_graph() recieves this json data, it populates a css popup, with the graph, and edits 5 buttons so they reference that UID. Those 5 buttons change the timescale of the graph by re-requesting the data from rrdjson.cgi.
What I am worried is happening, is that I click on the frige, it changes the uid's of the buttons inside the popup to reference the frige. Then I close that, click on the garage, it also changes the uid's and correctly shows the garage data. Then I click on one of the buttons inside the popup for the garage, and poof, I get the refrigerator again. I suspect that ajax "remembers" the old values for $(this).attr("href") etc and passes those values to the code, rather than re-reading the contents of the HTML. (perhaps instead of HTML, I meant DOM there, I'm a little vauge on the difference, but I suspect I meant DOM)
Maybe the answer is to somehow un-register the ajax binding to those buttons and re-register it every time make_graph() changes them? How would I do the un-register? .off() ? .unbind() ?
After much gnashing of teeth, and google, I have answered my own question.
https://forum.jquery.com/topic/jquery-data-caching-of-data-attributes
Turns out, jquery caches "data" types, but not attr types. So when I do:
uid = $(this).data("uid");
vs
uid = $(this).attr("data-uid");
I get wildly different results. I guess the moral of the story is that .data is super evil.. :)
If you add a random value to your url like
var formURL = $(this).attr("href")+"?rv="+Math.random();
you'll force the ajax call to reload the URL. You can use the cache property (set it to false) JQuery will load the data again, but any proxy may send a cached version.
(Please check that there are no other attributes set in the url, otherwise set "&rv="+Math.random(); (& instead of ?) use
var formURL = $(this).attr("href");
formURL + (formURL.indexOf("?") > 0 ? "&rv=" : "?rv=" )+ Math.random();
Your problem should not have something to do with make_graph() as uid and name depend on $('.graphbutton')
(if not make_graph(), or some other function, changes the attributes of your buttons)
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
I was asked to develop a tab panel with 6 tabs, each having 30 to 40 elements. Each tab is acting as a form in accumulating the details of a person and the last tab is a Summary page which displays all the values entered in the first five tabs. I was asked to provide summary as a tab because, the user can navigate to summary tab at any instance and look at the details entered by him/ or glace the summary. i am following ExtJs MVC pattern. Payload is coming from / going to Spring MVC Application. (JSON)
Using tab change event in controller and if the newtab is summary I am rendering the page with show hide functionality.
Method 1 :In controller I have used Ext.getCmp('id of each element inside the tabs') and show hide the components in summary tab based on the value entered by the user. This killed my app in IE8 popping a message saying that the "script is slow and blah blah..." i had to click on NO for 5 to 6 times for the summary tab to render and display the page.
Method 2 :In controller I used ref and selectos to acccess all the items in tabs. I have used itemId for each and every field in summary tab. like this.getXyz().show(). I thought it would be fast. Yes it was in Google chrome. but my app in IE8 is slow compared to goolge chrome/firefox
Any suggestions regarding this and plan to decrease page render time. The summary page has more than 1000 fields. Please feel free to shed ur thoughts or throw some ideas on this.
thank you!!
I've got a few suggestions you can try. First, to answer your title, I think the fastest simple way to lookup components in javascript is to build a hash map. Something like this:
var map = {};
Ext.each(targetComponents, function(item) {
map[item.itemId] = item;
});
// Fastest way to retrieve a component
var myField = map[componentId];
For the rendering time, be sure that the layout/DOM is not updated each time you call hide or show on a child component. Use suspendLayouts to do that:
summaryTabCt.suspendLayouts();
// intensive hide-and-seek business
// just one layout calculation and subsequent DOM manipulation
summaryTabCt.resumeLayouts(true);
Finally, if despite your best efforts you can't cut on the processing time, do damage control. That is, avoid freezing the UI the whole time, and having the browser telling the user your app is dead.
You can use setTimeout to limit the time your script will be holding the execution thread at once. The interval will let the browser some time to process UI events, and prevent it from thinking your script is lost into an infinite loop.
Here's an example:
var itemsToProcess = [...],
// The smaller the chunks, the more the UI will be responsive,
// but the whole processing will take longer...
chunkSize = 50,
i = 0,
slice;
function next() {
slice = itemsToProcess.slice(i, i+chunkSize);
i += chunkSize;
if (slice.length) {
Ext.each(slice, function(item) {
// costly business with item
});
// defer processing to give time
setTimeout(next, 50);
} else {
// post-processing
}
}
// pre-processing (eg. disabling the form submit button)
next(); // start the loop
up().down().action....did the magic. I have replaced each and every usage of Ext.getCmp('id'). Booooha... it's fast and NO issues.
this.up('tabpanel').down('tabName #itemIdOfField').actions.
actions= hide(), show(), setValues().
Try to check deferredRender is true. This should only render the active tab.
You also can try a different hideMode. Especially hideMode:'offsets ' sounds promising
Quote from the sencha API:
hideMode: 'offsets' is often the solution to layout issues in IE specifically when hiding/showing things
As I wrote in the comment, go through this performance guide: http://docs.sencha.com/extjs/4.2.2/#!/guide/performance
In your case, this will be very interesting for you:
{
Ext.suspendLayouts();
// batch of updates
// show() / hide() elements
Ext.resumeLayouts(true);
}