Update page with new data in Django - ajax

Let's imagine I have a Django app which can create and display some kind of articles which are stored in DB. Every article has a status value which means if status=1, it should be displayed, if status=0, it shouldn't.
I create articles on some page of my app, and by default it's status is 1. In the other tab the other page is opened. Every N seconds it sends AJAX requests with the ids of currently displayed articles and gets response with the id and content of new articles which are not displayed yet.
The question is - how can I dynamically render divs for new articles and fill them with data from response, if I don't want to create HTML-markup in success function of AJAX request with append() function or some kind of that stuff? I.e. I create article in one tab and it instantly displays in the other tab.

You can render a template with all new articles:
def new_article_view(request):
old_ids = request.query_params.get('ids')
new_articles = Articles.objects.exclude(id__in=old_ids.split(','))
# this render your template for Articles list.
return render(request, {'new_articles':new_articles}
then in your javascript code you most push the html returned by the django view in the end of the div or something like that.

Related

Page loading and state dependency between different components

I am building an application using React-Redux + React Router.
So, if user enters https://my-website.com/teams, I want to present him Teams page.
Lets suppose that my app consists of 2 components: Header and TeamsScreen.
I need to load user data to display Header.
I need to load user data & teams data to display TeamsScreen.
What is the right way to achieve it according to Best Practices?
What I have done so far:
1) Introduced a new component, lets name it AuthenticatedUser
render() {
if(!this.props.userData)
return (
<Loader/>
);
return (
<div>
<Header userData={this.props.userData}/>
<TeamsScreen userData={this.props.userData}/>
</div>
);
}
Which loads user data on componentDidMount.
If user data is null, it displays loader. If it's not null, it renders Header and TeamsScreen.
2) I give user data as property to Header. I give user data as property to TeamsScreen.
3) On componentDidMount in TeamsScreen I load teams data.
If teams data is null, I display loader for TeamsScreen. Otherwise I display TeamsScreen.
It seems working, but...In case of slow internet and/or slow database here is how it looks like:
1) There is a big loader for whole page while user data gets loaded.
2) As soon as it gets loaded, I display a header and loader gets moved a bit down till teams data is loaded and I can display TeamsScreen.
I have an uncomfortable feeling that I am doing something wrong.
Please correct me.
Thank you in advance!
Any hints / links to articles will be appreciated.
In this case you should use redux. All code related to fetch data from server will be in actions which which can first start spinner and in turn dispatch another action which will hide spinner and set your data once data returned from server.

Ajax state history in coldfusion page

I'm confused as to how to accomplish this. I have a page which, has a popup filter, which has some input elements and an "Apply" button (not a submit). When the button is clicked, two jquery .get() calls are made, which load a graph, a DataTables grid, photos, and miscellaneous info into four separate tabs. Inside the graph, if one clicks on a particular element, the user is taken to another page where the data is drilled down to a finer level. All this works well.
The problem is if the user decides to go back to the original page, but with the ajax generated graph/grid/photos etc. Originally I thought that I would store a session variable with the filter variables used to form the original query, and on returning to the page, if the session var was found, the original ajax call would be made again, re-populating the tabs.
The problem that I find with this method is that Coldfusion doesn't recognize that the session variable has been set when returning to the page using the browser's back button. If I dump out the session var at both the original and the second page, I can see the newly set var at the second page, and I can see it if I go to the original page through the navigation menu, but NOT if I use the back button.
SO.... from reading posts on here about ajax browser history plugins, it seems that there are various jquery plugins which help with this, including BBQ. The problem that I see with this approach is that it requires the use of anchor elements to trigger it, and then modifies the query string using the anchors' href attributes. I suppose that I could modify the page to include a hidden anchor.
My question, at long last is: is an ajax history plugin like BBQ the best way to accomplish this, or is there a way to make Coldfusion see the newly created session var when returning to the page via the back button? Or, should I consider re-architecting the page so that the ajax calls are replaced by a form submission back to the page instead?
Thanks in advance, as always.
EDIT: some code to help clarify things:
Here's the button that makes the original ajax calls:
<button id="applyFilter">APPLY</button>
and part of the js called on #applyFilter, wrapped in $(document).ready():
$('#applyFilter').click(function(){
// fill in the Photos tab
$.get('tracking/listPhotos.cfm',
{
id: id,
randParam: Math.random()
},
function(response){
$('#tabs-photos').html(response);
}
);
});
Finally, when the user calls the drill-down on the ajax generated graph, it uses the MaintAction form which has been populated with the needed variables:
function DrillDown() {
//get the necessary variables and populate the form inputs
document.MaintAction.action = "index.cfm?file=somepage.cfm&Config=someConfig";
document.MaintAction.submit();
}
and that takes us to the new page, from which we'd like to return to the first page but with the ajax-loaded photos.
The best bet is to use the BBQ method. For this, you don't have to actually include the anchor tags in your page; in fact, doing so would cause problems. This page: http://ajaxpatterns.org/Unique_URLs explains how the underlying process works. I'm sure a jQuery plugin would make the actual implementation much easier.
Regarding your other question, about how this could be done with session variables - I've actually done something similar to that, prior to learning about the BBQ method. This was specifically to save the state of a jqGrid component, but it could be easily changed to support any particular Ajax state. Basically, what I did was keep a session variable around for each instance of each component that stored the last parameters passed to the server via AJAX requests. Then, on the client side, the first thing I did was run a synchronous XHR request back to the server to fetch the state from that session variable. Using the callback method for that synchronous request, I then set up the components on my page using those saved parameters. This worked for me, but if I had to do it again I would definitely go with the BBQ method because it is much simpler to deal with and also allows more than one level of history.
Some example code based on your update:
$('#applyFilter').click(function(){
var id = $("#filterid").val(); // assumes the below id value is stored in some input on the page with the id "filterid"
// fill in the Photos tab
$.get('tracking/listPhotos.cfm',
{
id: id // I'm assuming this is what you need to remember when the page is returned to via a back-button...
//randParam: Math.random() - I assume this is to prevent caching? See below
},
function(response){
$('#tabs-photos').html(response);
}
);
});
/* fixes stupid caching behavior, primarily in IE */
$.ajaxSetup({ cache: false });
$.ajax({
async: false,
url: 'tracking/listPhotosSessionKeeper.cfm',
success: function (data, textStatus, XMLHttpRequest)
{
if (data.length)
{
$("#filterid").val(data);
$('#applyFilter').trigger('click');
}
}
});
This is what you need on the client-side to fetch the state of the photo list. On the server side, you'll need to add this modification to tracking/listPhotos.cfm:
<cfset session.lastUsedPhotoFilterID = URL.id>
And add this new one-line file, tracking/listPhotosSessionKeeper.cfm:
<cfif IsDefined("session.lastUsedPhotoFilterID")><cfoutput>#session.lastUsedPhotoFilterID#</cfoutput></cfif>
Together these changes will keep track of the last ID used by the user, and will load it up each time the page is rendered (whether via a back button, or simply by the user revisiting the page).

Google analytics and loading a page using ajax GET request

I have a mobile site which completely runs using AJAX, and hash code, basically each page click is a link, such as
<a href='http://some-domain.com/my-page-122.php" hash-id='122'>linkage</a>
Meaning that the page itself exists and it has ON IT google analytics page, HOWEVER, on the ajax request, I only ask to load a certein <div> on said page using jQuery's load(), so my question is:
because the page is called for in it's entirety with the google analytics code and everything, will it still record it as a page view even though only a portion is injected to the page?
The reason why I'm asking is because this site is getting around 500 uniques per day, and we want to change it to this new AJAXy form, so not recording analytics is a big no-no.
If you use jQuery you can bind to the global AjaxComplete event to fire a Pageview everytime an Ajax call completes:
jQuery(document).ajaxComplete(function(e, xhr, settings){
var d = document.location.pathname + document.location.search + document.location.hash;
_gaq.push(['_trackPageview', d]);
});
If you update the Anchor every time you do an Ajax call this will fire the full path including the anchor part of the url.
Note that if you load content using .load that has the Google Analytics Tracking code in it, it will run that code and fire a second pageview. So you want to make sure you don;t include the GATC on the ajax content to avoid double pageviews.
Analytics won't record it automatically. Assuming you're using the asynchronous code you can record as many pageviews as you want by writing to the gaq array using an explicitly set URL:
_gaq.push(['_setAccount', 'UA-12345-1']);
_gaq.push(['_trackPageview', '/home/landingPage']);
In this case you can build whatever URL you want where they have '/home/landingPage'. Note that if _gaq was already properly instantiated and _setAccount was already pushed then you only need to push the _trackPageview.
Also, the event can be in code returned by your AJAX, or it can be in the click event of your button or whatever is launching the AJAX request.
See http://code.google.com/apis/analytics/docs/gaJS/gaJSApiBasicConfiguration.html#_gat.GA_Tracker_._trackPageview

Selecting a div from prototype response Magento

Hello i am using Prototype javascript library in Magento.
I am getting an ajax response and everything is working fine.
The response is saved in the response variable.
var response = transport.responseText || "no response text";
What i want is to fetch a div and its content from the response variable. I am totally confused on how to do it.
I want to get the div and its content and replace it with the current div and its content.
I know how to do it by $('div').update('content') but i am not able to fetch the exact div the content within the div.
You could try something like this:
var container = new Element("div", {}).update(responseText); // this way you get a valid Prototype Element that you can easily query
// performs your query on the Prototype Element
// NOTE: remember to not include the root "div" when attaching your response to the html page
Hopefully I answered your question. If not, please add a sample of code of what you are trying to accomplish!

coldfusion session refresh

Is there a way to refresh coldfusion session on the page without reloading the page? Let's say I had 3 items in my shopping cart. Now I want to remove one of the items by clicking "remove" link next to a product. I created delete_item.cfm that removes a particular item from cart using jquery ajax. Now I want my shopping cart to display only 2 items without reloading the page. Here is my code.
<CFIF ISDEFINED("ProductID")>
<!--- Find where in the basket it is --->
<CFSET ItemPosition = ListFind(session.StoreItems,ProductID)>
<CFSET session.StoreItems = ListDeleteAt(session.StoreItems, ItemPosition, ",")>
<CFSET session.StoreItemsQty = ListDeleteAt(session.StoreItemsQty, ItemPosition, ",")>
This has little to do with ColdFusion specifically, and more to do with a very common Ajax design pattern. You've got most of it right; here's the general idea:
User clicks [delete].
A JavaScript handler function sends the ID of the item to be deleted to your delete_item.cfm handler on the server. Example:
$('a.deletelink').click( function(e){
e.preventDefault();
$.ajax({
url : '/handlers/delete_item.cfm',
data : $(this).data('id'),
type : 'post',
success : /* see below */
});
});
On the server, another function retrieves an updated view of the region of the page affected by the change -- now without the deleted item. delete_item.cfm calls this function and returns the updated view information to the Ajax requester. This could take the form of:
The raw data, perhaps in the form of a JSON string, or...
A fully rendered HTML version of the region to be re-drawn.
In the success handler of the Ajax call, the updated view information is received. You then:
Loop over the JSON data and build the appropriate HTML in JavaScript, then drop it into your container area (perhaps using a templating engine), or...
Drop in the fully rendered HTML as supplied from delete_item.cfm, replacing the older version that originally contained the item you're deleting.
Example:
/* success handler from above */
function(data){ // data is what's returned from delete_item.cfm
// Assuming it's fully rendered HTML post-deletion:
$('#container_of_your_list')
.html( data ) // drop in new data
.effect('highlight',{},2000); // visual feedback to user
}
Absolutely. When you make an AJAX request, you're making the request as the user... so if you make any changes to session, it will make those changes on the user's session. That being said, if you want to redraw the cart page, you'll need to do all of that with client-side javascript, just like you're making the AJAX call.

Resources