Refreshing dynamic form fields after data has changed - forms

I have a ColdFusion page that has, among other things, forms that are built using DataTables.
This page manages a handful of things (documents, categories, doctypes, etc) and each tab has CRUD functionality going on.
Initially, on each tab, it simply displays the current set of (fill in the blank) but if you click the create/update links/icons, the form to do so pops up. Some of the form fields are actually lists of the others. For example, if I want to upload a new document, one of the form fields is the category for that document.
I get the information for that form field by using cfinvoke to a get function in a cfc, which returns as a query and I loop through, populating the dropdown.
My problem is this: If I go and create a new category on the category tab I need the dropdown of category choices to update over on the new document form. However, it's already been populated and won't recheck that info until I refresh the page and thus won't show my new category in the dropdown.
The way I see it, I need to reinvoke the CFC method, repopulating the query variable and then refresh the form to make it loop through the new data and fully populate the dropdown.
I've tried to call the cfinvoke and reset the form from within the callbacks section of the DTHelper() but that (kind of as expected) didn't work.
How would I force the refreshing of the data, and subsequently, the form when this all takes place using AJAX and the actual page never reloads? Or should I just be forcing a page reload in this situation? (which works, I tried that, but it's a page refresh)

So, my boss figured it out. You have to use drawCallback().
In my example it worked like so. First, give all your major category select boxes a class:
<select name="majorCategoryID" class="major-category-select">
...
</select>
Then modify the DataTable options for major category:
majorcat_dt = $("#majorcat-dt").DataTable({
ajax: "blah"
columns: [{ blah }],
drawCallback: function() {
/* remove all options from select boxes */
$(".major-category-select option").remove();
/* this is the crazy DataTables api call to get rows */
this.api().rows().data().each(function(row) {
$(".major-category-select").append("<option value='"+row.id+"'>"+row.name+"</option>");
});
}
});
This also removed the need for the cfinvoke in the first place since this also populates the dropdowns on page load as well.

Here is how I did something like that once.
javascript:
var minutes = 10;
var refreshInterval = minutes * 60 * 1000; // to get milliseconds
jQuery.fn.populateCensusDiv = function() {
$.ajax({
type:"POST",
url:"censusData.cfc?method=getCensusData",
cache:false,
success: function(msg) {
$("#census").html(msg);
}
});
setTimeout(function() {
$("#census").populateCensusDiv();
}, refreshInterval);
return this;
ColdFusion function
<cffunction name="getCensusData" access="remote" returntype="string"
//deleted code
returnFormat = "plain">
<cfscript>
var returnString = "";
</cfscript>
more code
<cfsavecontent variable="returnString">
more code
</cfsavecontent>
<cfreturn returnString>
</cffunction>
My context was an html table that got refreshed every 10 minutes. You can adapt it for your own needs.

Related

What is the proper way to integrate dynamic content into the layout.ejs file in a Sails.JS application?

Say I wrote a blog app in Sails.js.
On every page in this app, there is a sidebar widget called "Recent Posts", where it lists the titles of the 5 most recent posts and clicking on them takes you to the post in question.
Because this sidebar widget is present on every page, it should be in layout.ejs. But, here we have a conflict - dynamic content is only supposed to be pulled from the database in the controller action for rendering a specific view.
This dynamic content isn't for a specific view, it's for the whole site (via layout.ejs).
By the conventions that I understand, I'd have to get that dynamic content data for the sidebar widget in every controller action that renders a view (otherwise I would get an undefined error when I attempt to call that local in my layout.ejs file).
Things I've tried / considered:
Load that dynamic content in every controller action that renders a view (this solution is very bad) and calling that dynamic content in layout.ejs as if it were a local for the specific view. This works fine, but goes against D.R.Y. principles and quite frankly is a pain in the ass to have to run the same query to the database in every controller action.
As per another similar stackoverflow question, create a new config (E.G. config/globals.js), load my dynamic content from my database into that config file as a variable, and then calling sails.config.globals.[variable_name] in my layout.ejs file. This also worked, since apparently config variables are available everywhere in the application -- but it 's a hacky solution that I'm not a fan of (the content I'm loading is simply the titles and slugs of 5 recent posts, not a "global config option", as the solution implies).
Run the query to get the dynamic content inside the .EJS file directly between some <% %> tags. I'm not sure if this would work, but even if it did, it goes against the separation of concerns MVC principle and I'd like to avoid doing this if at all possible (if it even works).
As per a lengthy IRC discussion # http://webchat.freenode.net/?channels=sailsjs, it was suggested to create a policy and map that policy to all my controllers. In that policy, query the database for the 5 most recent posts, and set them to the req.recentposts. The problem with this solution is that, while the recent posts data will be passed to every controller, I still have to pass that req.recentposts data to my view -- making it so I still have to modify every single res.view({}) in every action. I don't have to have the database query in every action, which is good, but I still have to add a line of code to every action that renders a view... this isn't D.R.Y. and I'm looking for a better solution.
So, what is the proper solution, without needing to load that dynamic content in every controller action (a solution that adheres to D.R.Y. is what I'm lookng for), to get some dynamic content available to my layout.ejs file?
In folder /config you should create a file express.js and add something like that:
module.exports.express = {
customMiddleware: function(app){
app.use(function(req, res, next){
// or whatever query you need
Posts.find().limit(5).exec(function(err, posts){
res.locals.recentPosts = posts;
// remember about next()
next();
});
});
}
}
Then just make some simple loop in your view:
<% for(var i=0; i<recentPosts.length; i++) { %>
<% recentPosts[i].title %>
<% } %>
Here are some links to proper places in documentation:
https://github.com/balderdashy/sails-docs/blob/0.9/reference/Configuration.md#express
and
https://github.com/balderdashy/sails-docs/blob/0.9/reference/Response.md#reslocals
I found out another way to do this. What I did was to create a service that could render .ejs files to plain html by simply taking advantage of the ejs library already in sails. This service could either be invoked by the controller, or even passed as a function in the locals, and executed from within the .ejs. The service called TopNavBarService would look like:
var ejs = require('ejs');
exports.render = function() {
/* database finds goes here */
var userInfo = {
'username' : 'Kallehopp',
'real_name' : 'Kalle Hoppson'
};
var html = null;
ejs.renderFile('./views/topNavBar.ejs', {'locals':userInfo}, function(err, result) { html = result; });
return html;
}
In the constroller it could look like:
module.exports = {
testAction: function (req, res) {
return res.view('testView', {
renderNavbar: TopNavBarService.render // service function as a local!
});
}
};
This way you can create your customized ejs-helper that could even take arguments (although not shown here). When invoked, the helper could access the database and render a part of the html.
<div>
<%- renderNavbar() %>
</div>

Serializing form exotic behaviour in AJAX response?

I have a page with few tabs. Data in each tab is ajax response once the user clicks tab.
Tab1 Tab2 Tab3
While coming to the page, we load Tabl with ajax response, in that serializing form.
After page loads, Editing form then checking is there any change to save the form data.
* Again serializing form and comparing old and new form.
It is working fine. But if i move to other Tab and come back to Tab1 serializing is not working as expected.
I kept alert and checked it. Orizinal form data serializing and new form also serializing and checking.
Even Data is same but
_sourcePage param is having different value.
I don't know why it is giving this strange behaviour.
Please help me.
Edit:
The code what i'm using is :
$(document).ready(function () {
originalSerializedForm = $("#Tab1").serialize();
});
function saveDataWhenFormChanged()
{
var newSerializedForm = $("#Tab1").serialize();
if(originalSerializedForm && newSerializedForm && newSerializedForm != originalSerializedForm){
alert('Original Form :'+originalSerializedForm+'\n'+'New Form :'+newSerializedForm);
$.ajax({
url : url,
data : newSerializedForm,
dataType: "html",
type : "POST",
beforeSend: function(){
openLoadingPopup();
}});
}
This happened due to zig-zag and not well formated html..
i was using form with in the other form.. which caused this..
i removed that.. it was working as expected..

How to reference dynamically added element after DOM loaded without a need to act on any events?

I know there is .on and .live (deprecated) available from JQuery, but those assume you want to attach event handlers to one ore more events of the dynamically added element which I don't. I just need to reference it so I can access some of the attributes of it.
And to be more specific, there are multiple dynamic elements like this all with class="cluster" set and each with a different value for the: title attribute, top attribute, and left attribute.
None of these jquery options work:
var allClusters = $('.cluster');
var allClusters2 = $('#map').children('.cluster');
var allClusters3 = $('#map').find('.cluster');
Again, I don't want to attach any event handlers so .on doesn't seem like the right solution even if I were to hijack it, add a bogus event, a doNothing handler, and then just reference my attributes.
There's got to be a better solution. Any ideas?
UPDATE:
I mis-stated the title as I meant to say that the elements were dynamically added to the DOM, but not through JQuery. Title updated.
I figured it out. The elements weren't showing up because the DOM hadn't been updated yet.
I'm working with Google Maps and MarkerClustererPlus to give some more context, and when I add the map markers using markerclustererplus, they weren't available in the javascript code following the add.
Adding a google maps event listener to my google map fixed the problem:
google.maps.event.addListener(myMarkerClusterer, 'clusteringend', function () {
// access newly added DOM elements here
});
Once I add that listener, all the above JQuery selectors and/or methods work just fine:
var allClusters = $('.cluster');
var allClusters3 = $('#map').find('.cluster');
Although this one didn't, but that's because it only finds direct decendants of parent:
var allClusters2 = $('#map').children('.cluster');
Do what you need to do in the ajax callback:
$.ajax(...).done(function (html) {
//append here
allClusters = $('.cluster');
});
If you want them to be separate, you can always bind handlers after the fact, or use $.when:
jqxhr = $.ajax(...).done(function (html) { /* append html */ });
jqxhr.done(function () { allClusters = $('.cluster') });
$.when(jqxhr).done(function () { /* you get it */ });
If these are being appended without ajax changes, then just move the cluster-finding code to wherever the DOM changes take place.
If that's not an option, then I guess you would just have to check on an interval.

Validation Forms that were loaded via Ajax into jquery-ui tabs

I'm using jquery-ui tab example to add extra tabs. I changed that code to be able to add tabs that load a form via Ajax. I was able to create that just changing these:
var $tabs = $( "#tabs").tabs({
cache: true,
tabTemplate: "<li><a href='formularioAgricola.php' id='#{label}'>#{label}</a> <span class='ui-icon ui-icon-close'>Remove Tab</span></li>"
//ajaxOptions: a
});
So I changed the tabTemplate to load the same Form always.
My problem is that I'm not sure how to retrieve, either to tell that every tag from that form use jquery-ui stuff, like buttons, datepickers, etc.
In a regular form I would do something like:
$("#btnRevisar").button()
But when we talk about form load via Ajax it is different.
and also, how can I try to differ one form from other one, if they are all named with the same name, is it possible?
Thanks guys
Carlos.
Within the tabs docs page, tab titled "Events" there is a "load" event. The "ui" argument gives you access to an object that includes the current panel that is loaded. If you are using same ID on forms, beware that ID's must be unique in a page.
var $tabs = $( "#tabs").tabs({
cache: true,
tabTemplate: "<li><a href='formularioAgricola.php' id='#{label}'>#{label}</a> <span class='ui-icon ui-icon-close'>Remove Tab</span></li>",
/* add new option for load event*/
load: function( event, ui){
var $currTabContentPanel=$(ui.panel);
/* only look in currently loaded content for formClass*/
$currTabContentPanel.find('.formClass').doSomething()
}
});

ASP.net MVC Set Checkboxes to checked Clientside

My situation is: Im making a simple inbox page. The inbox is a listing made from a DevExpress grid. Each row in the grid has a checkbox that the user can check so that they can multi delete records (similar to yahoo mail etc).
When the user clicks the select all link or the clear all link i need to set all the checkboxes within the grid to be checked or unchecked. How do I go about this with client-side scripting? Thanks
The easiest way to do this is to use jQuery. With the right selector it's pretty much a one liner. I don't know how much you know about jQuery so here's a link to the selector docs if you want to read up:
http://api.jquery.com/category/selectors/
The selector will depend on the layout of your page. I've done it before using something like this:
$("#tableId tr td input:checkbox").attr("checked", true);
In this example all checkboxes within a table with an id of "tableId" are checked
Using jquery it should be pretty easy- assuming you can use one of the selectors to select all of the checkboxes (take a look at the different jquery selectors http://api.jquery.com/category/selectors/).
Attach a toggle handler:
$('Selector for the "select all" checkbox>').toggle(function() {
alert('First handler for .toggle() called.');
}, function() {
alert('Second handler for .toggle() called.');
});
Select all checkboxes and when toggled switch the checked state of the other checkboxes:
$('<Selector for the ones you want to toggle>').attr('checked', true);
Provide some sample HTML, or a link to a page, if you need further help.
So putting it together, assuming your "select all" checkbox had an ID of "uxSelectAll" and the ones you want to change have a CSS class of "checkbox-mail-items" it would be something like:
$('#uxSelectAll').toggle(function() {
$('.checkbox-mail-items').attr('checked', true);
}, function() {
$('.checkbox-mail-items').attr('checked', false);
});
you can create a delegate (jquery) for all the checkboxes once you've done the answer above. with something like to perform an action for each check box:
$('div.myGridDivClass tbody').delegate(':checkbox', 'click', function(){
var $checkedRow = $(this), $row = $checkedRow.closest('tr')
// check row is checked
// toggleclass for checked css class and apply to the $row or whatever u want
// do something here
});