I have some elements in my HTML which are generated entirely by jQuery, and then removed when no longer needed.
Something along these lines:
var div = $('<div/>').attr('id', 'addedItem');
$('body').append(div);
For example, then when closed we do:
$('#addedItem').remove();
BUT… during the course of it’s use, we might change the classes of addedItem due to adding another feature to it, for example, adding tinyMCE to a textArea
$('#textAreaId').tinymce({ vars });
Adds a rich text editor to a text area (providing all the correct scripts are loaded), I have added a new line to the end of tinymce():
$(applyTo).addClass('editorLoaded');
To stop the code from trying to add the editor to the same element twice.
This all works lovely… BUT…
If I close this window down and thus call the line $('#addedItem').remove(); and then later on (without page reload) I want to re-add to the page and display again, the classes added to the elements remain.
So, in short. An element with an ID addedItem is added to the body by jQuery, stuff is done to it and it gets a class attribute added to it. After it’s finished with jQuery completely removes the element. A bit later on, we add a new element with the ID addedItem to the body using jQuery again, it’s a fresh element, but yet it retains it’s class attribute added before removal!
According to jQuery DOCS remove() behaviour should be:
In addition to the elements themselves, all bound events and jQuery
data associated with the elements are removed.
Which I take to mean it should remove any classes added to the elements with jQuery as well as data etc… maybe I am reading it wrong, misinterpreting, or something else!
Can anyone help me to remove these elements and ALL references to them in browser memory/cache/whatever so I can manage this issue.
jQuery version is 1.7.1 if that’s any help
========== EDIT > MORE CODE ADDED ================
The above outlined my problem, here’s the actual code then
// create a modal window with a top right X closer from any element
$.fn.makeModal = function (vars) {
var theId = $(this).attr('id');
var exists = false;
try {
if ($('#' + theId + '_wrap').length > 0) { // firstly check the element has already been "made modal"
exists = true;
};
} catch (err) {
exists = false;
};
if (!exists) { // if this is the first time
var win = this;
var h;
var w;
var persist;
var alert;
if (vars) {
h = vars.height;
w = vars.width;
persist = vars.persist;
alert = vars.alert;
};
if (typeof h == "string") {
h = (h.replace('px', '') * 1); // clean out px if dimensions posted in px
};
if (typeof w == "string") {
w = (w.replace('px', '') * 1); // clean out px if dimensions posted in px
};
var hRatio = 0.70;
var wRatio = 0.5;
var minW = 480;
if (!h) { h = $(window).height() * hRatio }; // default case if no height passed
if (!w) {
w = $(window).width() * wRatio;
minW = 480;
if (w < minW) { w = minW };
}; // default case if no width passed
// **** END BASIC VARIABLES
var wrapper = $('<div/>').attr('id', theId + '_wrap').addClass('modalContainer').css({ 'top': ($(window).height() - h) / 2, 'left': ($(window).width() - w) / 2, 'width': w, 'height': h }); // create a wrapper for the main content
var close = $('<span/>').addClass('closeModal').html('X').css({ 'z-index': getMaxZIndex() + 5 });
// creat close button
if (alert) {
$(close).addClass('alert');
$(wrapper).addClass('alert');
} else {
$(close).addClass('cross');
};
if (persist) {
$(wrapper).addClass('persist');
}; // persist variable allows you to determine whether to delete or simply hide element on close
$(win).addClass('modalContent').css({ 'display': 'block', 'width': w - 20, 'height': h - 20 }).appendTo(wrapper);
$('body').append(wrapper).opaqueBg();
$(wrapper).prepend(close).fadeIn('fast').css({ 'z-index': getMaxZIndex() + 3 });
$(close).modalCloser();
$(document).on('keyup', function (e) {
if (e.keyCode == 27) {
closeModal(wrapper);
$(document).unbind('keyup');
};
});
} else {
$('body').opaqueBg();
$('#' + theId + '_wrap').fadeIn('fast') // .children().css({ 'display': 'block' });
};
// END OF MODAL WINDOWS
};
The jQuery function above creates a modal window out of any element dynamically created or otherwise.
Associated functions for closing etc:
// top right X closer actions
$.fn.modalCloser = function (callBack) {
$(this).bind('click', function () {
$(this).closest('div.modalContainer').fadeOut(function () {
closeModal(this, callBack);
});
});
};
// close modal element by item
function closeModal(ele, callBack) {
if (!ele) {
ele = '.modalContainer'
};
if ($(ele).hasClass('noClose')) {
alert("Please wait... we're working on something.");
} else {
$(ele).fadeOut(function () {
var nextZ = getMaxZIndex('.modalContainer');
if (nextZ > 0) {
$('#screenBlank').css({ 'z-index': nextZ });
} else {
$('#screenBlank').fadeOut(function () { $(this).remove(); });
};
if (!$(this).hasClass('persist')) {
$(this).remove();
};
if (callBack) {
callBack();
};
});
};
};
// end modal window controls
// ****************************************************************************************************************************************************************
// create opaque background for modal window to sit on
$.fn.opaqueBg = function () {
$('#screenBlank').remove();
var z = getMaxZIndex() + 2;
var sb = $('<div/>').attr('id', 'screenBlank').addClass('noPrint centreLoader').css({ 'display': 'none', 'position': 'absolute', 'text-align': 'center', 'z-index': z, 'background-color': 'rgba(10, 0, 0, 0.7)', 'width': '100%', 'height': $(document).height(), 'top': '0px', 'left': '0px' });
$('body').prepend(sb);
$(sb).fadeIn().bind('click', function () {
closeModal('.modalContainer');
});
};
// find the maximum z-Index of elements on the page, used to ensure tooltips are always shown above anything else
// note, this will only work if major containing elements have explicitly set z-index
function getMaxZIndex(ele) {
if (!ele) {
ele = "div";
};
var zIndexMax = 0;
$(ele).each(function () {
if ($(this).css('display') != "none") {
var z = parseInt($(this).css('z-index'));
if (z > zIndexMax) { zIndexMax = z };
};
});
return zIndexMax;
};
// end finding maximum z-index
So all of the above is a generic set of functions for all kinds of purposes within my project.
The particular purpose that prompted this post was creating a textarea within a modal window with tinymce applied, this works like this:
$('#notePad .plus').on('click', function () {
var h = $('<h2/>').html('Add Note');
var txt = $('<textarea/>').attr('id', 'noteEditorContent').attr('name', 'newNote').css({ 'width': '100%', 'height': '400px' });
var wrpper = $('<div/>').css({ 'width': '750', 'height': '380', 'margin': 'auto' }).append(txt);
var button = $('<span/>').addClass('greenButton').html('Save').css({ 'float': 'right', 'margin': '40px 20px 0px 20px', 'width': '80px' }).bind('click', function () {
saveStaffNote($('#noteEditorContent').val(), true);
});
var div = $('<div>').attr('id', 'notePadEditor').append(h).append(wrpper).append(button);
$(txt).richEditor('simple', function () {
$(div).makeModal({ 'width': '800', 'height': '530', 'persist': true });
// CALLING THE makeModal() function above
});
});
AND FINALLY, the application of tinymce is this function:
// === loading Rich Text Editors //
$.fn.richEditor = function (theTheme, callBack) {
var applyTo = this;
var tinyMceVars = {
// Location of TinyMCE script
script_url: '/Admin/Plugins/richEditor/tiny_mce.js',
// General options
theme: theTheme,
plugins: "autolink,lists,pagebreak,style,layer,table,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,searchreplace,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,advlist",
// Theme options
theme_advanced_buttons1: "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,formatselect,fontselect,fontsizeselect,|,bullist,numlist,|,undo,redo,|,code,preview,fullscreen,|,cleanup,help",
theme_advanced_buttons2: "cut,copy,paste,pastetext,|,insertdate,inserttime,|,link,unlink,anchor,image,|,forecolor,backcolor,|,search,replace",
theme_advanced_buttons3: "tablecontrols,|,hr,removeformat,visualaid,|,charmap,emotions,iespell",
theme_advanced_toolbar_location: "top",
theme_advanced_toolbar_align: "left",
theme_advanced_statusbar_location: "bottom",
theme_advanced_resizing: true,
relative_urls: false,
remove_script_host: false,
document_base_url: window.location.protocol + "//" + window.location.hostname,
external_link_list_url: window.location.protocol + "//" + window.location.hostname + "/Admin/Scripts/Lists/link_list.js",
external_image_list_url: window.location.protocol + "//" + window.location.hostname + "/Admin/Scripts/Lists/image_list.js"
};
if ($(applyTo).hasClass('editorLoaded') == false) {
try { // try to apply the editor, if fails it's because the scripts are not loaded, so load them!
$(applyTo).tinymce(tinyMceVars);
} catch (err) {
$.getScript("/Admin/Plugins/richEditor/jquery.tinymce.js", function () {
$(applyTo).tinymce(tinyMceVars);
});
} finally { // finally apply richEdit class to avoid re-writing and perform a callback if required
$(applyTo).removeClass('richEdit').addClass('editorLoaded');
if (callBack) {
callBack();
};
};
};
};
I believe your problem is that you are adding the class to a jQuery object which is also referenced by the variable called
div. Try squirreling that variable away inside a function (javascript has function scope).try this instead: