UI5: accessing DOM ref of a view after rendering during each navigation - javascript

I have two UI5 XML views and the navigation has been implemented between both the views. Whenever I visit the second view, I manipulate the HTML DOM (using jQuery and CSS) to do some look and feel related changes which is not readily available in UI5 by default.
My issue is: When I wrote jQuery code to manipulate DOM in (route)patternMatched handler of second view, it is not working as DOM does not exist at that point. When I put the jQuery code in onAfterRendering() of second view, it gets executed only during first visit so not giving the desired result during 2nd visit onwards.
Can you tell me how to get rid of this issue or what design change I should make here?
Also, do we have any setting in UI5 by which onAfterRendering() will be called every time when I navigate to a view?

You can use the onBeforeShow method to do the manipulations required by you.
The onBeforeShow will be called every time the view is about to be shown to the screen.
But first you have to attach the event to the view in onInit.
Code:
onInit : function () {
this.getView().addEventDelegate({
onBeforeShow : jQuery.proxy(function(evt) {
this.onBeforeShow(evt);
}, this)
});
},
onBeforeShow: function() {
console.log('called from on Before show');
// DO manipulation here
}
If, you still don't find the DOM elements in this event handler, remember onBeforeShow has a sister: onAfterShow which will be called after the view is shown on screen.
API Link : NavContainerChild

Related

How to use intern leadfoot waitForDeletedByXpath function?

On what scenario can i use intern's leadfoot waitForDeletedByXpath function? From the documentation, what I understood is this method waits for the element to become invisible in Page. But while implementing it doesn't seem so. The scenerio i'm using this is as follows:
There is a page in my application where i can search for data with some predefined arguments. After clicking on search button the loading icon appears on the page until the data is loaded in the datagrid and the loading icon disappears after the data is loaded . so I'm trying to use this function to wait until the loading icon disappears from the page so that i can read the data in datagrid without having any issue but it doesn't seems to work that way.
Can someone please throw some light on how this function works and point me towards the right direction to achieve what i'm trying to do.
thanks
I believe what's happening here is a slight misinterpretation of what the waitForDeletedByXPath method does.
What the documentation for this method says is:
"Waits for all elements inside this element matching the given name attribute to be destroyed."
When your loading icon disappears it is most likely still part of the DOM, albeit it is just set to invisible. This method expects the element to no longer be part of the DOM at all.
What you need to do, from my experience, is set up your own "wait for element to be invisible" method for your loading icon.
For example:
return this.remote
.then(function () {
const waitForLoadingIconNotDisplayed = function (remoteSession) {
return remoteSession
.findByCssSelector('your_loading_icon_css_selector')
.isDisplayed()
.then(function (isDisplayed) {
if (isDisplayed) {
return waitForLoadingIconNotDisplayed(remoteSession);
}
return true;
});
};
return Promise.all([waitForLoadingIconNotDisplayed(this.parent)]);
})
This will loop until the condition is met that your loading icon is no longer set as displayed in the UI using the Promise.all() call.
Hope this helps steer you along the right path!

JavaScript heap size ever increasing with AJAX calls

I am designing a web application, and the app requires that I use AJAX to navigate pages, so the same frame is static, but the inner content changes, like
$(".nav > div").on('click',function(){
var id = $(this).attr('id');
$(".active").removeClass("active");
$(this).addClass("active");
$("#main").load("/page" + id + ".html");
});
which will load page1.html, following me clicking on the element with the id '1', for example.
I then use
$(document).ajaxComplete(function() {...javascript...});
to run the rest of my script which will be interacting with the inner content. My script contains numerous functions like
$('#fade').on('click', function() {
$('#zoom').removeClass('grow').addClass('shrink');
which interact with unqiue id's, all of which are similar in each of the '/page[number].html' files.
My script runs fine if I run it on an entirely static page, but as soon as I start introducing the AJAX element of reloading the html in the inner frame, the website gets slower and slower every time I make an AJAX call - by using the .nav bar - until a crash. The javascript heap size seems to increase almost exponentially, see:
http://imgur.com/0mvoOjA
Not only the js heap size is ever increasing, but it also seems 'paint' is taking up a lot of memory. Each page I am loading a new, fairly high res image, could this be related?
I am fairly new to AJAX calls so any pointers would be appreciated! Thanks
It's likely that you're creating event handlers with $().on on the other pages and you aren't explicitly removing them before you navigate to another page.
$(element).on(event, function() {
// ...
});
When you make an event listener like this jQuery maintains a reference to the function, meaning it can't be garbage collected. Every time you navigate to a new page, you create more event handlers that can't be automatically removed.
function eventHandler() {
// ...
}
// when the page is loaded
$(element).on(event, eventHandler);
// just before you leave
$(element).off(event, eventHandler);
Better still, when you know there only needs to be one interaction with the element before you'll navigate away, you can use one, to create an event listener that will be called only once before it is automatically dereferenced.
$(element).one(event, eventHandler);
// don't worry about removing these handlers
How you structure this code is best determined by your existing application architecture.
You need to unbind the events. If not, you are binding and binding events to your element instead of override it. You can do it with $('#yourElement').unbind('click');

Parse.View: event isn't working when I exit the view and enter it again

I'm using Parse JS in version 1.3.4 in a web app project
<script src="//www.parsecdn.com/js/parse-1.3.4.min.js"></script>
in one of my Views, I have this declaration:
var DrivesView = Parse.View.extend({
className :'backbone-container',
options: {},
events: {
"click i.map-view-open-button": "openMapViewInModal"
},
I wanted to put an event in a font awesome element, which has the class map-view-open-button. Parse is somehow different than Backbone on this...
This works pretty well like this:
reload the page
go to the view (by clicking on the menu)
click on the <i> element --> my function app.driveView.openMapViewInModal runs ok
I can open the modal (run the function) several times, it works.
BUT, if I click on the menu and go to another view, and then come back to app.driveView, then the event won't work. The function app.driveView.openMapViewInModal won't be called if I click on the <i> element.
The strange parte is that the event is still there in the view. I checked it with app.drivesView.events.
Do I need to somehow close the view when I leave (how?) and then render it again so that the events will be recreated?
This is what I tried so far. I thought that I can delete the event on the render function, and create it again. The problem is that the render function will be called only once (at the first visit). If I leave the view and come back, the render function won't be called, which is really strange since my router points to this function (where render is explicitly called):
drivesViewer: function(){
$('#app').html(this.driveView.render().el);
},
any ideas?
thanks.
I finally found a solution. It is really strange and against my expectation, but I'm not an expert, so my expectation is not really "valid".
here is what I did. On the viewer function I remove the view:
drivesViewer: function(){
this.drivesView.remove();
$('#app').html(this.driveView.render().el);
},
Then, inside the 'DrivesView' declaration, I removed the 'events' attribute and put this lines in the 'render' function:
this.undelegateEvents();
this.delegateEvents({"click i.map-view-open-button": "openMapViewInModal"})
now, each time the view is loaded, I remove the view, then I undelegate the envents (not sure if really needed), then set new events. It works.
Note: I think there is a difference between Backbone and Parse here, don't really know why. Any comment and discussion on this is appreciated.

How can I get a partial view to load on button click?

I have a scenario where I’m using Ajax.ActionLink() to call and load a child view in a parent view. I have a button on the child view that calls another child view. I would like for this child view to also show on the parent view.
I could load the child view into the calling child view if I use Ajax.ActionLink and it would look as if it’s in the parent view which is fine but the button offers me more benefits including sending stuff in the beginform and checking the field before submitting.
When the user clicks on the button it sends selected data from two drowdown lists as well as other data in BeginForm like:
#using (Html.BeginForm("Action", "Controller", new { courseID = 1001 }, FormMethod.Post, new { #id = "formName", #name = "formName" }))
However when the view returns it opens in a new window not in the parent view or the child view that called it.
How can I get the partial view to show in the child view that calls it or on the parent. Meaning parent calls child A and child A calls child B.
Reason #2,343,657 why I despise the Ajax.* family of helpers. They hide functionality, such that when something doesn't work as you expect, you don't know why. Write your own AJAX; you'll never be sorry you did.
Anyways, your problem here is that Ajax.ActionLink writes JavaScript to the page that wires all this functionality up for you. You didn't write that JavaScript (and apparently didn't even know it was there), but it was there, nonetheless.
Now that you've switched to using Html.BeginForm, that JavaScript has gone away, leaving nothing but a standard HTML form, that causes a page reload on submit. If you want the same functionality, you could use Ajax.BeginForm instead. But, before you run off and do that, take the opportunity to improve your code and write the JavaScript yourself. Then, things are very explicit, and you (or another developer) never have to wonder how it works, because it's right there.
All you need to do is attach a handler to the form's submit event, serialize the form, then post it over AJAX, and then do something with the response. I'm going to use jQuery for this example because 1) AJAX is one of those things you should use some sort of framework for to avoid a bunch of repetitive boilerplate code and 2) since it comes with an MVC project by default, there's a fair chance you already have to there and available to use.
$(document).ready(function () {
$('#YourForm').on('submit', function (e) {
e.preventDefault();
$.post('/url/to/post/to', $(this).serializeArray(), function (result) {
// do something with `result`
// For example, if `result` is a string of HTML, you can just
// write it out to some element:
$('#ResultDiv').html(result);
});
});
});

loadmask in sencha touch2

I want apply load-mask in view page. while launching the application, some view pages are taking time to load data later it will display, so if its taking time to load in that time i want show load-mask to users with some messages like "loading....". from some sample i have applied load-mask, but it is shows that message every time whenever i hit that page. this is bad way because here setting time. i need apply load-mask like this if don't have data it should show the load-mask to the user, until page getting the data. please any one help me. how to achieve this one
My code is here: at controller level i am taking the id of load-mask and setting the property as shown below code
onCompanyPageLoad: function () {
var loader = Ext.getCmp('mask');
loader.setMessage("Loading...");
loader.setIndicator(true);
loader.setTransparent(false);
loader.show();
setTimeout(function () {
loader.hide();
}, 1000);
}
The answer of user978790 is formal way to show and hide a loading mask in Sencha Touch 2.
If you can't make it work, it's very likely that you're doing something like:
Ext.Viewport.setMasked({xtype:'loadmask',message:'your custom loadmask'});
... then do something here
Ext.Viewport.setMasked(false);
Note that Javascript is asynchronous, so it does NOT make sure that the code lines are run in above order. Then there is a possibily that Sencha Touch initializes your loading mask and destroys it right then. In order to use loading mask correctly:
Initialize a loading mask as above.
Put the Ext.Viewport.setMasked(false); in special functions which are ensured to be launched after loading mask initialization, eg. event handler, or success function of your JSONP/AJAX request.
I do it the following way:
Ext.Viewport.setMasked({xtype:'loadmask',message:'your custom loadmask'});
Then you can use
Ext.Viewport.setMasked(false);
To stop showing a loading mask
This also works on components if you only want to show a mask on part of a view
Just remove all this.I have nice idea how to use loader.First on main page html just add loader
<div id="loader"></div>//add id#loader with background loading image
after your page loads just add on contoller Ext.get('loader').destroy();//when you page full load then it will load your loading div

Categories