MDL animations stop working on copied <fieldset> - javascript

I am having an issue when cloning a section of my form (with jQuery).
The code below copies a 'fieldset', applies unique id's and for's, then appends the copy within the original 'fieldset'.
Although the copying works, all animations of the 'MDL'framework break on the copied 'fieldset'.
The code I am using is shown below:
//When add section is pressed
$('#add-section').click(function () {
// add 2 vars to count clicks per page
// get the fieldset's children that user is on, and clone it
var $fieldsetCopy = $('form>:nth-child(' + pageNumber + ')').clone();
// add '-2' to all id's of the cloned fieldset
$fieldsetCopy.find("*[id]").each(function () {
$(this).attr("id", $(this).attr("id") + "-2");
});
// add '-2' to all for's of the cloned fieldset
$fieldsetCopy.find("*[for]").each(function () {
$(this).attr("for", $(this).attr("for") + "-2");
});
// remove the first p element of the clone
$fieldsetCopy.find("p").first().remove();
// add the cloned fieldset within the original
$fieldsetCopy.appendTo('form>:nth-child(' + pageNumber + ')');
$()
});
I was guessing a problem be the JavaScript loading?

I ended up finding the answer myself. The problem was that the framework needed to be reloaded. To do this you can use the line:
componentHandler.upgradeAllRegistered();
Or, if you would like to target a specific element you can use:
componentHandler.upgradeElement(button);
The full documentation is here https://getmdl.io/started/#dynamic

Here is another example (without jQuery). Maybe it will help. Just rebuild the DOM manually.
<script type="text/javascript">
document.getElementById("addText").onclick = function () {
var form = document.getElementById("container_layout_text");
var newDiv = document.createElement("div");
newDiv.className = "mdl-textfield mdl-js-textfield mdl-textfield--floating-label desc_value";
var newInput = document.createElement("input");
newInput.className = "mdl-textfield__input";
newInput.type = "text";
var newLabel = document.createElement("label");
newLabel.className = "mdl-textfield__label";
newLabel.textContent = "kkk?";
newDiv.appendChild(newInput);
newDiv.appendChild(newLabel);
componentHandler.upgradeElement(newDiv);
form.appendChild(newDiv);
}

Related

Changing a dynamically created label's text with keyup() issue

I am creating a form dynamically and therefore edit the form elements’ properties. When attempting to change the label, assigning an auto-generated id works fine but when changing this label using the generated id, the function or keyup() from jQuery keeps calling all the previously created label id(s). this means when i want to edit one label, it ends up editing every label.
HTML
<input type="text" id="change-label"><br><br>
<button id="add-button">add label</button>
<div id="add-label"></div>
JavaScript/jQuery
$('#add-button').click(function(){
var div = document.createElement('div');
var textLabel = document.createElement('label');
var labelNode = document.createTextNode('untitled');
textLabel.appendChild(labelNode);
textLabel.id = autoIdClosure();
$('#change-label').val('untitled');
div.appendChild(textLabel);
$('#add-label').append(div);
});
var autoIdClosure = (function(){
var counter = 0;
var labelId = "textInputLabel";
return function(){
counter += 1;
var id = labelId + counter;
editLabelWrapper(id)
return id;
}
})();
function editLabelWrapper(id){
function editLabel(){
var value = $(this).val();
$("#"+id).text(value);
}
$("#change-label").keyup(editLabel).keyup();
}
I’ve already found an alternative using onkeyup="$('#'+globaID).text($(this).val());", but I need to understand what I was doing wrong so I can learn from it.
JSFiddle
I think you are overthinking the matter...
Instead of using an unique id, rather use classes, makes it easier to handle.
So change <div id="add-label"></div> to <div class="add-label"></div>
Then what you want to do is, when a value is given in #change-label you want it in the last div.add-label.
So the function will become this:
$("#change-label").on('keyup', function() {
$('.add-label:last').text( $(this).val() );
});
Next what you want to do is bind a function to #add-button. Once it gets clicked, we want to add a new div.add-label after the last one. And empty the #change-label. You can do that by using this function:
$('#add-button').on('click', function() {
$('.add-label:last').after('<div class="add-label"></div>');
$('#change-label').val('');
});
Updated Fiddle

DOM: Delete newly created 'article' element with newly created delete button within onclick event?

I have one section element that contains one article element. Also, I have one input button with 'onclick' event. Whenever this event fired, a new article element appended to the section element with unique id.
The newArticle element contains a label, text box and a delete button. All these three elements get created within the on-click event.
document.getElementById("addRow").onclick = function () {
var newCustomerlbl = document.createElement("label");
newCustomerlbl.innerHTML = "Cutomer Name: ";
var newCustomertxt = document.createElement("input");
newCustomertxt.setAttribute("type", "text");
var delBtn = document.createElement("input");
delBtn.setAttribute("type", "button");
delBtn.setAttribute("value", "Delete");
delBtn.setAttribute("id", "btnDelete");
var newArticle = document.createElement("article");
newArticle.appendChild(newCustomerlbl);
newArticle.appendChild(newCustomertxt);
newArticle.appendChild(delBtn);
var customerSection = document.getElementById("customerRecords");
var customerArticles = customerSection.getElementsByTagName("article");
for (var i = 0; i < customerArticles.length; i++) {
var lastDigit = i + 1;
var newArticleValue = "article" + lastDigit;
newArticle.setAttribute("id", newArticleValue);
}
customerSection.appendChild(newArticle);
}
Now what I want is whenever user click upon the newly created appended delete button, only that particular article get deleted without effecting the rest of articles.
Here is the my jsFiddle code.
If you don't want to use jQuery you can add event listeners to your buttons:
delBtn.addEventListener('click', function () {
this.parentElement.remove();
}, false);
https://jsfiddle.net/3nq1v5e1/
You need to bind an event listener on the newly created delete button. Your example code about using $(this) suggest that you are using JQuery, but then again in the rest of the code you are not using any JQuery?
If you are using JQuery, things get real simple, just add something like
$(document).on('click','.btnDelete', function(){
$(this).closest('article').remove();
});
(and remember to give the deletebutton a CLASS rather than ID, as there will be multiple delete buttons).
If you are NOT using JQuery, you need to add the event listener EVERY TIME a new delete button is created
newArticle.appendChild(delBtn);
delBtn.onclick = function(.....
etc.

Changing JavaScript into jQuery - createElement

I'm trying to use the draggable and resizable jQuery function, but I may have to change a little bit of this code to jQuery.
I have this HTML code:
<div id="resizable2" class="ui-widget-content">
<h3 class="ui-widget-header">MS</h3>
</div>
This works great with the jQuery:
$(function() {
$( "#resizable" ).draggable();
$( "#resizable" ).resizable();
}
But then, I've tried to use it with a div created by javascript:
function addnewbox() {
var newDiv = document.createElement("div");
var h = document.createElement("h3");
var text = document.createTextNode("MS");
document.body.appendChild(newDiv);
newDiv.appendChild(h);
newDiv.className = "ui-widget-content";
h.appendChild(text);
h.className = "ui-widget-header";
newDiv.id = "resizable";
}
And it's not working
Change your dom object to a jQuery object by calling $(newdiv) and re-initialise the resizable and draggable functionality on the new content.
function addnewbox() {
var newDiv = document.createElement("div");
var h = document.createElement("h3");
var text = document.createTextNode("MS");
newDiv.appendChild(h);
newDiv.className = "ui-widget-content";
h.appendChild(text);
h.className = "ui-widget-header";
newDiv.id = "resizable";
$(newDiv).resizable(); //Add this
$(newDiv).draggable(); //and this
document.body.appendChild(newDiv); //Append to the dom once you've finished with it.
}
As devqon has mentioned, the reason for this is that this function adds dynamic content (content which isn't there on page load) this means that the draggable and resizable functionality is not present on this new content. This is why you need to re-initialise the connection between the new element and the functionality.
Also as menioned don't re-use ID's, they must be unique. It is bad practice to use the same id for multiple elements and will very likely lead to other issues.
Lastly, it is a good idea when creating new content to manipulate it first and add it to the page at the end. In this instance you are appending further content inside the newly created div. I would do this first and then when finished with it, add it to the page.
Hi I have changed your function to:
function addnewbox() {
var newDiv = document.createElement("div");
var h = document.createElement("h3");
var text = document.createTextNode("MS");
newDiv.id = "resizable";
newDiv.className = "ui-widget-content";
h.className = "ui-widget-header";
h.appendChild(text);
newDiv.appendChild(h);
document.body.appendChild(newDiv);
}
And I have created a jsfiddle for you to try yourself:
http://jsfiddle.net/ttw7218z/4/
Well you need to initialize resiazble plugin on new DOM elements. You already have a few JS solutions so I will post one more version using jQuery for elements creation:
function addnewbox() {
$('<div class="ui-widget-content resizable">' +
'<h3 class="ui-widget-header">MS</h3>' +
'</div>').appendTo('body').resizable();
}
One more thin you should be aware of: you should not duplicate ids, they must be unique. So instead of multiple #resizable use .resizable classes.

Recursive IDs and duplicating form elements

I have the following fiddle:
http://jsfiddle.net/XpAk5/63/
The IDs increment appropriately. For the first instance. The issue is when I try to add a sport, while it duplicates, it doesn't duplicate correctly. The buttons to add are not creating themselves correctly. For instance, if I choose a sport, then fill in a position, and add another position, that's all fine (for the first instance). But when I click to add another sport, it shows 2 positions right away, and the buttons aren't duplicating correctly. I think the error is in my HTML, but not sure. Here is the JS I am using to duplicate the sport:
$('#addSport').click(function(){
//increment the value of our counter
$('#kpSport').val(Number($('#kpSport').val()) + 1);
//clone the first .item element
var newItem = $('div.kpSports').first().clone();
//recursively set our id, name, and for attributes properly
childRecursive(newItem,
// Remember, the recursive function expects to be able to pass in
// one parameter, the element.
function(e){
setCloneAttr(e, $('#kpSport').val());
});
// Clear the values recursively
childRecursive(newItem,
function(e){
clearCloneValues(e);
});
Hoping someone has an idea, perhaps I've just got my HTML elements in the wrong order? Thank you for your help! I'm hoping the fiddle is more helpful than just pasting a bunch of code here in the message.
The problem is in your clearCloneValues function. It doesn't differentiate between buttons and other for elements that you do want to clear.
Change it to:
// Sets an element's value to ''
function clearCloneValues(element){
if (element.attr('value') !== undefined && element.attr('type') !== 'button'){
element.val('');
}
}
As #PHPglue pointed out in the comments above, when new positions are added, they are incorrectly replicated (I'm assuming here) to the newly cloned for
There is a similar problem with the add years functionality.
A quick fix would be to initialize a variable with a clone of the original form fields:
var $template = $('div.kpSports').first().clone();
Then change your addSport handler to:
$('#addSport').click(function () {
//increment the value of our counter
$('#kpSport').val(Number($('#kpSport').val()) + 1);
//clone the first .item element
var newItem = $template.clone();
…
});
However, there are no event bindings for the new buttons, so that functionality is still missing for any new set of form elements.
Demo fiddle
Using even a simple, naive string based templates the code can be simplified greatly. Linked is an untested fiddle that shows how it might be done using this approach.
Demo fiddle
The code was simplified to the following:
function getClone(idx) {
var $retVal = $(templates.sport.replace(/\{\{1\}\}/g, idx));
$retVal.find('.jsPositions').append(getItemClone(idx, 0));
$retVal.find('.advtrain').append(getTrainingClone(idx, 0));
return $retVal;
}
function getItemClone(setIdx, itemIdx) {
var retVal = itemTemplate.replace(/\{\{1\}\}/g, setIdx).replace(/\{\{2\}\}/g, itemIdx);
return $(retVal);
}
function getTrainingClone(setIdx, trainingIdx) {
var retVal = trainingTemplate.replace(/\{\{1\}\}/g, setIdx).replace(/\{\{2\}\}/g, trainingIdx);
return $(retVal);
}
$('#kpSportPlayed').on('click', '.jsAddPosition', function() {
var $container = $(this).closest('.kpSports');
var containerIdx = $container.attr('data_idx');
var itemIdx = $container.find('.item').length;
$container.find('.jsPositions').append(getItemClone(containerIdx, itemIdx));
});
$('#kpSportPlayed').on('click', '.jsAddTraining', function() {
var $container = $(this).closest('.kpSports');
var containerIdx = $container.attr('data_idx');
var trainIdx = $container.find('.advtrain > div').length;
$container.find('.advtrain').append(getTrainingClone(containerIdx, trainIdx));
});
$('#addSport').click(function () {
var idx = $('.kpSports').length;
var newItem = getClone(idx);
newItem.appendTo($('#kpSportPlayed'));
});

Jquery: Blur function does not work with Div tag

I am trying to create a Jquery Tree plugin for my current project. In the plugin, there are 3 compomnents: a text box containing the result selected from the tree , a div containing the tree and a button to show the div. It works fine, except that i cannot make it auto lose the popup div if the tree lose its focus.
Here is the code to create the div
createTree = function() {
$.getJSON(_options.jsonSrc, function(data) {
nDiv = document.createElement("div");
nDiv.id = "divRootAd";
$(nDiv).css('display', 'none');
jsonObj = data["treeJson"];
nUl = document.createElement("ul");
nUl.appendChild(createNode(jsonObj));
nDiv.appendChild(nUl);
$("body").append(nDiv);
//$(nDiv).focus();
repositionDiv();
});
};
repositionDiv = function() {
if ($('#divRootAd').is(':hidden')) {
// get the field position
var sf_pos = $("#txtAdVal").offset();
var sf_top = sf_pos.top;
var sf_left = sf_pos.left;
// get the field size
var sf_height = $("#txtAdVal").height();
// apply the css styles - optimized for Firefox
$("#divRootAd").css("position","absolute");
$("#divRootAd").css("left", sf_left);
$("#divRootAd").css("top", sf_top + sf_height + 5);
$('#divRootAd').show();
$('#divRootAd').blur(function(event){
alert("lose focus");
clearDiv();
});
} else {
clearDiv();
}
};
The line alert("lose focus") does not work when i move the mouse outside the div. Can anyone suggest a solution for this ?
Instead of blur you could use mouseout
$('#divRootAd').mouseout(function(event){
alert("lose focus");
clearDiv();
});
Hope it helps

Categories

Resources