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

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()
}
});

Related

Refreshing dynamic form fields after data has changed

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.

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>

ExpressionEngine: Conditionally display custom fields in a channel entry form

I'm building a blog site in ExpressionEngine. I have two types of entries that I want to keep in the same channel. When a certain category is selected i'd like to show additional fields.
**EXAMPLE
Channel > Article
Fields:
- Title
- Post Body
- Image
- Tags
Additional Fields for a category:
- Price
- Product Bio
Is this possible?
How savvy are you with JavaScript? You could use Brandon Kelly's CP CSS & JS extension. Then use a little custom javascript to build that functionality. Not perfect, but probably faster than writing a custom extension. Roughly, you'd do this:
Create the channel fields group and all the channels, and assign that group to your channel
To make it a little more usable, you'll want the category selector to be on the same Publish tab as the fields: Create a custom publish layout for that channel that moves the Categories field from the Categories tab to the Publish tab
Find the id numbers of the channel fields that you want to hide, as those will be HTML IDs in the Publish page that look like "hold_field_ID#"
Figure out the category ID for the category to click to reveal additional fields. In the Publish page, that category will show up in the Categories field with a "value=ID" attribute.
Script time! Head to Add-ons > Extensions > CP CSS & JS settings and add some JS in the Custom Javascript field.
Something like this:
$(document).ready(function() {
// Cache the divs with your channel fields
var $theSecretFields = $('#hold_field_5, #hold_field_6');
// Hide them
$theSecretFields.each(function() {
// But only if they're empty (no previous saved data)
// If you're using a textarea or something else, change the .find selector
if ( $(this).find('input').val() === '' ) { $(this).hide() };
});
// When you click the category ID (the input[value="id"] selector)...
$('#hold_field_category').find('input[value="12"]').click(function() {
// Toggle the visibility of the channel fields
// Again, only show/hide them if they're empty
$theSecretFields.each( function() {
// Again, change the .find selector for your field type if necessary
if ( $(this).find('input').val() === '' ) { $(this).toggle() };
});
});
};
You might have to build in some more logic in the click handler to make sure that the fields are only shown when the checkbox is selected (among other things), but that's the basic idea.
You want this within the control panel or the front end of the site?
To do this with categories as the trigger, you'll need to write a custom extension that adds the javascript to do your showing and hiding.
You might want to look at the Entry Type add-on, which allows you to use a dropdown menu to change the fields which are displayed.

Enabling/Disabling CSS based on Session value using MVC

I am rather new to MVC applications, and one thing I am trying to accomplish is enabling or disabling stylesheets based on a Session value.
I have stylesheets referenced in my Site.Master page in this manner:
<%=Html.Stylesheet("~/styles/main.css", "string")%>
<%=Html.Stylesheet("~/styles/additions.css", "string")%>
Right now, for testing, I have been putting an if statement around the Html.Stylesheet tags saying:
<% if (Session["cssRule"] = "enableCss") { %>
<%=Html.Stylesheet("~/styles/main.css", "screen")%>
<%=Html.Stylesheet("~/styles/additions.css", "screen")%>
<%} %>
So if the 'cssRule' Session value is null, no CSS loads. Currently this is working fine, but it is not exactly what I am looking for. Right now I set the Session value in the Controller when the user logs in, but ultimately I need to set the value of the Session variable depending on if a user clicks the enable or disable button. Since I have been primarily using webforms for the past year and a half, I just want to drop a hyperlink and set an event for it, but alas, this is the future of MVC so I need to figure out how I can do something like this..
So my real question is how can I set the Session of the "cssRule" value by clicking a link using MVC?
I'll assume you want to use a standard link (not ajax) and that your main view is Index
Just add a method in your controller (pseudocode)
public ActionResult ToggleCSS()
{
if (Session["cssRule"] != null && Session["cssRule"] == "enableCSS")
{
Session["cssRule"] = "disableCSS";
}
else
{
Session["cssRule"] = "enableCSS";
}
return View("Index");
}
Then in your view, use
<%= Html.ActionLink("ToggleCSS", "ControllerName") %>
You can use lots of fancy different methods to obtain the same result; use ajax and relaod the page, or not, or redirect to a page listing css files to apply, etc... but this one should work :)

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
});