I have a web application developed using Kendo UI.It has different pages containing filter,search bars,grids etc.
Let there be two pages page A and page B, If I have done some operations on page A (Seach operation and filling a form) then I have navigate to page B to refer some data and came back to the previous page A. But all the operations done on page A (Search and form data) are gone , the page is loaded like a fresh page.
Is there any way to save the state of the page A so that when I came back to page A from page B I will have all my previous work.
$("#landingPage").hide();
$("#mf").hide();
$("#wf").show();
var contentWf="#sd_cont_wf";
// $("#sd_cont_wf").html("");
if (!_currentView) {
constants.sessionDefaults.user = JSON.parse(localStorage.getItem("user"));
domReady(function () {
require(["domReady", "app/views/common/home"], function (domReady, homeView) {
domReady(function () {
$('#app-layout').html("");
_currentView = new homeView();
if (!_app) {
showApp();
}
_app.showIn("#app-layout", _currentView);
_currentView.showIn(contentWf, view);
});
});
});
} else {
$(".user_settings_menu").hide();
if(wf==0){
_currentView.showIn(contentWf, view);
constants.wfView=_currentView;
// var htmlData=$(contentWf).html();
// view.render("#sd_cont_wf");
// $("#sd_cont_wf").append(view.render);
wf=1;
}
}
Related
I'm still trying to master jQuery, AJAX, and JSON.
On my application, I have the following dropdown select menu:
<select id="serviceload" name="serviceload"></select>
I auto populate the OPTIONS with another function which I don't think is necessary to display here. Just know that the above SELECT has 1 or more OPTION values.
This is followed by the content section:
<div class="row" id="completeProfile">
// series of DIVS and TABLES
</div>
Initially, the content section is hidden, so the user will only see the dropdown menu:
$('#completeProfile').hide();
And now, the jQuery: this next piece of code is what I use when the user chooses a selection from the dropdown menu. Every time they pick a new selection, queries rerun, and new content is displayed to the screen, unless they select a blank OPTION.
$('#serviceload').change(function () {
var page = $('#serviceload').val();
if (page == "") {
$('#completeProfile').hide();
} else {
$.post('api/profileSearch.php', {
page: page
}, function (data) {
var obj = JSON.parse(data);
$('#portBody').empty();
var htmlToInsert = obj.map(function (item) {
return '<tr><td>' + item.PORT + '</td><td>' + item.NAME + '</tr>';
});
$('#portBody').html(htmlToInsert);
});
// I do several more $.post to return data into specific tables
// Take note of this next $.post
$.post('api/vesselSearch.php', {
page: page
}, function (data) {
var obj = JSON.parse(data);
$('#vesselinfo').empty();
var htmlToInsert = obj.map(function (item) {
return '<tr><td>Edit</td><td>' + item.VESSEL_NAME + '</td></tr>';
});
});
// after all the queries are ran, and the data is returned, now we show the content
$('#completeProfile').show();
}
});
In the vesselInfo portion above, there is section that prints a hyperlink with which you can click, and it opens a modal window. This is for editing purpose. This functions properly.
Here is where the issue lies.
Back in the content section, there is another hyperlink that opens a modal window to add a new vessel.
<h3>Vessels</h3> / Add New
This opens an Add New Vessel modal. In that modal there is a FORM with a button that reads like this:
<button type="button" id="addVesselSubmit">Add</button>
When this button is clicked, it sends the values entered by the user to a PHP script which updates a table.
$('#addVesselSubmit').click(function () {
var addservice = $('#addservice').val();
var addvessel = $('#addvessel').val();
$.post('api/addInfo.php', {
addservice: addservice,
addvessel: addvessel
}, function (data) {
// here is where my problem lies
if (data == 0) {
alert("Vessel was not saved");
} else {
alert("Vessel was saved");
// At this point, I need to rerun the main function above so that it shows the vessel that was added immediately to the content section without a page refresh
}
});
});
So in the code directly above, if the new record was successfully saved to the table, the whole content section should rerun without a page refresh, with the new record automatically showing in the vesselInfo section.
I think the code that is used to display the content needs to be turned into a main function that can be called when the addVesselSubmit is successful, but I am not sure how to proceed with that.
To reiterate my question: I need to be able to save a new record, and print the new record to the page without a page refresh.
$.post('api/addInfo.php', {
addservice: addservice,
addvessel: addvessel
}, function (data) {
// here is where my problem lies
if (data == 0) {
alert("Vessel was not saved");
} else {
alert("Vessel was saved");
// At this point, I need to rerun the main function above so that it shows the vessel that was added immediately to the content section without a page refresh
//Trigger a change on element
$('#serviceload').trigger('change');
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
}
});
I have the below JS code. This code basically starts a timer based on variables passed in when the page loads. This works fine on one tab. So basically if different section of the page are opened in different tabs based on the last server visit I want to refresh the timeout variable so that when the time ends the user is signed out from all the tabs and not just the current tab.
I want this:
window.setTimeout(promptToExtendSession, localStorage.getItem("secondsBeforePrompt1") * 1000);
to be refreshed in all the tabs if the
localStorage.getItem("secondsBeforePrompt1")
gets updated through any tab.
I am assigning values to the LocalSTorage variable on the server side.
var SessionManager = function() {
var endSession = function() {
$('#sessionTimeOutModal').modal('hide');
location.href = expireSessionUrl;
};
var startSessionManager = function () {
promptToExtendSessionTimeoutId =
window.setTimeout(promptToExtendSession, localStorage.getItem("secondsBeforePrompt1") * 1000);
};
// Public Functions
return {
start: function() {
startSessionManager();
},
extend: function() {
refreshSession();
}
};
}();
SessionManager.start();
I am using sammy.js for single page application in asp.net mvc. Everything is fine, but I am facing one problem which is that I can not reload the page. For example When I am in the dashboard my URL is
http://localhost:1834/#/Home/Index?lblbreadcum=Dashboard
layout.cshtml
<script>
$(function () {
var routing = new Routing('#Url.Content("~/")', '#page', 'welcome');
routing.init();
});
</script>
routing.js
var Routing = function (appRoot, contentSelector, defaultRoute) {
function getUrlFromHash(hash) {
var url = hash.replace('#/', '');
if (url === appRoot)
url = defaultRoute;
return url;
}
return {
init: function () {
Sammy(contentSelector, function () {
this.get(/\#\/(.*)/, function (context) {
var url = getUrlFromHash(context.path);
context.load(url).swap();
});
}).run('#/');
}
};
}
I want to reload the page by clicking the dashboard menu/link. But click event not firing because link is not changing. But if I want to go another page then it is fine. Please help me out. Thanks.
I think you have to append the same partial again. You can't "update" the partial in that meaning.
As you say in your post, when you click another link and then back again it works.
That's what you'll have to do. Append the same page/partial again, by doing that you clear all variables and recreate them, by that simulating a refresh.
EDIT: Added example
Observe that I didn't copy your code straight off but I think you'll understand :)
And I don't use hash (#) in my example.
var app = Sammy(function () {
this.get('/', function (context) {
// context is equalient to data.app in the custom bind example
// currentComponent('home'); I use components in my code but you should be able to swith to your implementation
var url = getUrlFromHash(context.path);
context.load(url).swap();
});
this.bind('mycustom-trigger', function (e, data) {
this.redirect('/'); // force redirect
});
this.get('/about', function (evt) {
// currentComponent('about'); I use components in my code but you should be able to swith to your implementation
var url = getUrlFromHash(context.path);
context.load(url).swap();
});
}).run();
// I did an easy example trigger here but I think you will need a trigger on your link-element. Mayby with a conditional check wheter or not to trigger the manually binding or not
$('.navbar-collapse').click(function () {
app.trigger('mycustom-trigger', app);
});
Please read more about events and routing in sammy.js
Good luck :)
An easier and cleaner way to force the route to reload is to call the Sammy.Application refresh() method:
import { sammyApp } from '../mySammyApp';
const url = `${mySearchRoute}/${encodeURIComponent(this.state.searchText)}`;
if (window.location.hash === url) {
sammyApp.refresh();
else {
window.location.hash = url;
}
So i'm learning AngularJS and i'm building a small web app that allows you to click through images randomly. Basically you click the next button and an image is downloaded and shown, when you click the back button it goes to the previous image in the stack.
I'd like to show a loading spinner and disable the back/forward buttons until the ajax request for the new image is complete, AND the image is completely loaded
My image controller is structured like so:
app.controller('ImageController', ['imageService', function(imageService) {
var that = this;
that.position = 0;
that.images = [];
that.loading = false;
that.isLoading = function() {
return that.loading;
}
that.setLoading = function(isLoading) {
that.loading = isLoading;
}
that.currentImage = function() {
if (that.images.length > 0) {
return that.images[that.position];
} else {
return {};
}
};
that.fetchSkin = function() {
that.setLoading(true);
imageService.fetchRandomSkin().success(function(data) {
// data is just a js object that contains, among other things, the URL for the image I want to display.
that.images.push(data);
that.imagesLoaded = imagesLoaded('.skin-preview-wrapper', function() {
console.log('images loaded');
that.setLoading(false);
});
});
};
that.nextImage = function() {
that.position++;
if (that.position === that.images.length) {
that.fetchSkin();
}
};
that.previousImage = function() {
if (that.position > 0) {
that.position--;
}
};
that.fetchSkin();
}]);
If you notice inside of the that.fetchSkin() function, i'm calling the imagesLoaded plugin then when the images are loaded I am setting that.loading to false. In my template I am using ng-show to show the images when the loading variable is set to false.
If I set loading to false outside of the imagesLoaded callback (like when the ajax request is complete) then everything works as expected, when I set it inside of the imagesLoaded function the template doesn't update with the new loading value. Note that the console.log('images loaded'); does print to the console once the images have loaded so I know the imagesLoaded plugin is working correctly.
As your imagesLoaded callback is invoked asynchronously once images are loaded, Angular does not know that values of that.isLoading() method calls changed. It is because of dirty checking that Angular uses to provide you with easy to use 2 way data binding.
If you have a template like so:
<div ng-show="isLoading()"></div>
it won't update after you change the values.
You need to manually tell angular about data changes and that can be done by invoking $digest manually.
$scope.$digest();
just after you do
console.log('images loaded');
that.setLoading(false);
Pseudo code that can work (copied and pasted from my directive):
//inside your controller
$scope.isLoading = false;
// just another way of using imagesLoaded. Yours is ok.
$element.imagesLoaded(function() {
$scope.isLoading = true;
$scope.$digest();
});
As long as you only change your controller $scope within async callback, there's no need to call $apply() to run $digest on $rootScope because your model changes are only local.
I'm in a real bottleneck with backbone.
I'm new to it, so sorry if my questios are stupid, as i probably didn't get the point of the system's structure.
Basically, I'm creating ad application which lets you do some things for different "steps". Therefore, I've implemented some kind of pagination system. Each time a page sasisfies certain conditions, the next page link is shown, and the current page is cached.
Each page uses the same "page" object model/view, and the navigation is appended there each time. it's only registered one time anyway, and I undelegate/re-delegate events as the old page fades out and the new one fades in.
If I always use cached versions for previous pages, everything is okay. BUT, if I re-render a page that was already rendered, when I click "go next page", it skips ahead of how many times i re-rendered the page itself.
it's like the "go next page" button has been registered, say, 3 times, and was never removed from the events listener.
It's a very long application in terms of code, and i hope you can understand the basica idea, and give me some hints, without needing to have the full code here.
Thanks in advance, i hope somebody can help me out since i'm in a real bottleneck!
p.s. for some reason, I've noticed that the next/previous buttons respective html is not cached within the page. Weird.
---UPDATE----
I tried the stopListening suggestion, but it didn't work. Here is jmy troublesome button:
// Register the next button
App.Views.NavNext = Backbone.View.extend({
el: $('#nav-next'),
initialize: function() {
vent.on('showNext', function() {
this.$el.fadeIn();
}, this)
},
events: {
'click': 'checkConditions'
},
checkConditions: function() {
//TODO this is running 2 times too!
console.log('checking conditions');
if (current_step == 1)
this.go_next_step();
vent.trigger('checkConditions', current_step); // will trigger cart conditions too
},
go_next_step: function() {
if(typeof(mainView.stepView) != 'undefined')
{
mainView.stepView.unregisterNavigation();
}
mainView.$el.fadeOut('normal', function(){
$(this).html('');
current_step++;
mainView.renderStep(current_step);
}); //fadeout and empty, then refill
}
});
Basically, checkConditions runs 2 times as if the previousle rendered click is still registered. Here is where it's being registered, and then unregistered after the current step fades off (just a part of that view!):
render: function() {
var step = this;
//print the title for this step
this.$el.attr('id', 'step_' + current_step);
this.$el.html('<h3>'+this.model.get('description')+'</h3>');
// switch display based on the step number, will load all necessary data
// this.navPrev = new App.Views.NavPrev();
// this.navNext = new App.Views.NavNext();
this.$el.addClass('grid_7 omega');
// add cart (only if not already there)
if (!mainView.cart)
{
mainView.cart = new App.Models.Cart;
mainView.cartView = new App.Views.Cart({model: mainView.cart})
mainView.$el.before(mainView.cartView.render().$el)
}
switch (this.model.get('n'))
{
case 5: // Product list, fetch and display based on the provious options
// _.each(mainView.step_values, function(option){
// console.log(option)
// }, this);
var products = new App.Collections.Products;
products.fetch({data:mainView.step_values, type:'POST'}).complete(function() {
if (products.length == 0)
{
step.$el.append('<p>'+errorMsgs['noprod']+'</p>')
}
else {
step.contentView = new App.Views.Products({collection: products});
step.$el.append(step.contentView.render().$el);
}
step.appendNavigation();
});
break;
}
//console.log(this.el)
return this;
},
appendNavigation: function(back) {
if(current_step != 2)
this.$el.append(navPrev.$el.show());
else this.$el.append(navPrev.$el.hide());
this.$el.append(navNext.$el.hide());
if(back) navNext.$el.show();
navPrev.delegateEvents(); // re-assign all events
navNext.delegateEvents();
},
unregisterNavigation: function() {
navNext.stopListening(); // re-assign all events
}
And finally, here is the main view's renderStep, called after pressing "next" it will load a cached version if present, but for the trouble page, I'm not creating it
renderStep : function(i, previous) { // i will be the current step number
if(i == 1)
return this;
if(this.cached_step[i] && previous) // TODO do not render if going back
{ // we have this step already cached
this.stepView = this.cached_step[i];
console.log('ciao'+current_step)
this.stepView.appendNavigation(true);
if ( current_step == 3)
{
_.each(this.stepView.contentView.productViews, function(pview){
pview.delegateEvents(); //rebind all product clicks
})
}
this.$el.html(this.stepView.$el).fadeIn();
} else {
var step = new App.Models.Step({description: steps[i-1], n: i});
this.stepView = new App.Views.Step({model: step})
this.$el.html(this.stepView.render().$el).fadeIn(); // refill the content with a new step
mainView.cached_step[current_step] = mainView.stepView; // was in go_next_step, TODO check appendnavigation, then re-render go next step
}
return this;
}
Try using listenTo and stopListening when you are showing or removing a certain view from the screen.
Take a look at docs: http://backbonejs.org/#Events-listenTo
All events are binded on initialization of the view and when you are removing the view from the screen then unbind all events.
Read this for detailed analysis: http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/