Reputation: 247
I'm creating a web application that utilizes popups. I'm using the same popups on several pages, but with various differences between pages. This is all controlled through JavaScript (jQuery).
So, I decided to create a jQuery plugin to make those changes easily. The problem is that the listeners I created in the plugin definition aren't firing on click or even being shown as bound to those elements in the inspector. I'm not sure what the problem is, because it should be no different than binding events through functions.
Here's my code:
(function($) {
// Plugin Definition
$.fn.popup = function(options){
console.log("Popup Initializing");
// Override default settings with instance settings
var settings = $.extend({}, $.fn.popup.defaults, options);
console.log("Settings merged");
// Saving objects passed into function
var els = this;
console.log("Attaching Edit Event Listener");
// EDIT
//alert(settings.contentSelector + " " + settings.editButtonSelector);
$("#content").on("click", ".table .edit", function() {
console.log("Edit button clicked");
settings.isEdit = true; settings.isAdd = false;
row = $(this).parent();
header = row.siblings(settings.tableHeaderRowSelector);
headerCells = header.children();
titleCell = row.children(":first").text();
$(settings.popupHeaderSelector).html("Editing '" + titleCell + "'"); // set header
$(settings.popupOriginalIdSelector).val(row.children().eq(0).html());
$(settings.popupSubmitSelector).html("Update"); // set submit button text
// Generate and write form DOM to page
if (settings.autoGeneratePopupForm){
formContent = generateFormContent(headerCells, row); // Generate form inputs
optionsCurrentValues = formContent[1]; // Grab current option input values
$(settings.popupContentSelector).html(formContent); // write form contents to DOM
// set options to correct current settings
$.each(optionsCurrentValues, function(index, value) {
$("select[name='"+index+"']").val(value);
});
}
showPopup();
focusFirstEl();
});
console.log("Adding Add Event Listener");
// ADD
$(settings.contentSelector).on("click", settings.addButtonSelector, function() {
console.log("Add button clicked");
settings.isAdd = true; settings.isEdit = false;
headerCells = $(this).siblings();
row = $(this).parent().next(".row").children().not(".icon");
$(settings.popupHeaderSelector).html("Add New " + dataType); // set header
$(settings.popupSubmitSelector).html("Add " + dataType); // set submit button text
// Generate and write form DOM to page
if (settings.autoGeneratePopupForm){
formContent = generateFormContent(headerCells, row); // Generate form inputs
$(settings.popupContentSelector).html(formContent); // write form contents to DOM
}
showPopup();
focusFirstEl();
});
console.log("Adding Cancel Event Listener");
// CANCEL
$(settings.popupCancelSelector).click(function() {
hidePopup();
});
console.log("Adding User Enter Submission Prevention");
// PREVENT ENTER SUBMIT
$(settings.popupSelector + " form").keydown(function(event) {
var keycode = (event.keyCode ? event.keyCode : event.which);
if(keycode == '13') {
event.preventDefault();
return false;
}
});
console.log("Finished Initializing");
console.log("");
console.log(settings);
// Ensures chainability
return this;
};
/**
Generates form inputs based on the passed parameters.
@param headerRow the header row of the associated DOM table.
Must be from PHP generated DOM. See ImgsrcUI->printTable
@param contentRow the row of the associated DOM table to generate
the form inputs from. Must be from PHP generated DOM
See ImgsrcUI->printTable
@returns an array. 1st index is of generated form DOM, 2nd index is of current values of the inputs
*/
function generateFormContent(headerCells, contentRow){
formContent = ""; // Empty string filled with generated DOM
contentRow.children().not(".icon").each(function(index) {
inputType = headerCells.eq(index).attr("data-inputtype"); // Get type of input this cell should be
inputLabel = headerCells.eq(index).attr("data-inputlabel"); // Get the text for the label for this cell
cellVal = settings.isEdit == true ? $(this).text() : ""; // Get current value of cell
name = inputLabel.replace(/ /g,''); // Removed spaces from input label to generate the name attr for the input
optionsCurrentValues = {}; // assoc array of input name and value so that it can be set after applied to DOM
switch (inputType){
case "text":
formContent += '<label>'+inputLabel+'</label> <input name="new'+name+'" type="'+inputType+'" value="'+cellVal+'">'
break;
case "select":
options = headerCells.eq(index).attr("data-selectoptions"); // get string version of var name
options = eval(options); // assign that var value to options
formContent += '<label>'+inputLabel+'</label> <select name="new'+name+'" id="">'+options+'</select>';
optionsCurrentValues["new"+name] = cellVal;
break;
case "textarea":
formContent += '<label>'+inputLabel+'</label> <textarea name="new'+name+'" ></textarea>';
break;
}
});
return [formContent, optionsCurrentValues];
}
// Shows the popup and darkens the background
function showPopup(){
$(settings.darkenBackgroundSelector).show();
$(settings.popupSelector).show();
};
// Hides the popup and lightens the background
function hidePopup(){
$(settings.darkenBackgroundSelector).hide();
$(settings.popupSelector).hide();
}
// Puts focus on the first form element in the popup
function focusFirstEl() {
//$(popupSelector+" form").children(":first").focus();
$(settings.popupSelector + " form :input:visible:enabled:first").focus();
};
// Default Settings
$.fn.popup.defaults = {
autoGeneratePopupForm: false, // If true, the contents of the popup will be overwritten with a generated form inputs based on the data you click "edit" on. If false, no content is overwritten.
dataType: "data", // The name of the data type (Ex "Users", "Albums"). Used in the header of the popup
// General Selectors
darkenBackgroundSelector: "#darken-page", // The selector to darken the page behind the popup
contentSelector: "#content", // The selector for the main content area
// DOM Table Selectors
tableHeaderRowSelector: ".heading",
editButtonSelector: ".table .edit",
addButtonSelector: ".table .heading .add",
// Popup Selectors
popupSelector: ".popup.edit",
//popupContentSelector: this.popupSelector + " .content",
popupHeaderSelector: this.popupSelector + " .header p",
popupOriginalIdSelector: this.popupSelector + " #originalId",
popupSubmitSelector: this.popupSelector + " .footer .submit",
popupCancelSelector: this.popupSelector + " .cancel",
// Utility options. Don't change.
isEdit: false,
isAdd: false,
};
$.fn.popup.defaults.popupContentSelector = $.fn.popup.defaults.popupSelector + " .content";
$.fn.popup.defaults.popupHeaderSelector = $.fn.popup.defaults.popupSelector + " .header p";
$.fn.popup.defaults.popupOriginalIdSelector = $.fn.popup.defaults.popupSelector + " #originalId";
$.fn.popup.defaults.popupSubmitSelector = $.fn.popup.defaults.popupSelector + " .footer .submit";
$.fn.popup.defaults.popupCancelSelector = $.fn.popup.defaults.popupSelector + " .cancel";
}(jQuery));
and I'm calling it on the page like so:
$("html").popup({
autoGeneratePopupForm: true,
dataType: "User"
});
Any ideas? Thanks in advance.
Upvotes: 1
Views: 399
Reputation: 247
Somehow, I overlooked a simple issue.
Since my JS wasn't within a $(document).ready(function() {});
,
it was running as soon as the <script>
tag was encountered, which was before the DOM was rendered on the page.
Therefore, the JS was trying to bind to elements that didn't yet exist on the page.
Hope this helps anyone that stumbles upon this issue. Always make sure the DOM you're manipulating is actually on the page.
Upvotes: 1