Material Design Lite Table - Adding Rows Dynamically Breaks Format - javascript

This is the markup for the checkbox using material-design-lite:
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="checkbox">
<input type="checkbox" id="checkbox" class="mdl-checkbox__input" />
<span class="mdl-checkbox__label">Checkbox</span>
</label>
Problem is, that the labels for is connected to the inputs id.
So when I add dynamically a new checkbox, I have to also add an id. But how do I find out which Id to add? Wouldn't it be a problem, when I am later going to add these rows into a database?
Here is the working example:
http://codepen.io/anon/pen/QjNzzO
Notice the checkbox of the new task you add

As mentioned, you need to upgrade the element. You could call componentHandler.upgradeDom() instead of componentHandler.upgradeElement().
http://codepen.io/pespantelis/pen/pjbvBL

Material Design Lite will automatically register and render all elements marked with MDL classes upon page load. However in the case where you are creating DOM elements dynamically you need to register new elements using the upgradeElement function.
To upgrade all elements, use this code:
componentHandler.upgradeAllRegistered();
http://www.getmdl.io/started/index.html#dynamic
How Component Handler works?

My personnal approach is to create a component. I have a working one here in coffeescript and jade
Basically you need to call componentHandler.upgradeElements(el). Last time I checked this wasn't enough as it wasn't adding the ripple effect so you also need to upgrade the lastChild. Please note there's a difference with componentHandler.upgradeElement(el) and componentHandler.upgradeElements(el) which, if I recall correctly, walk deeply the dom.
About the problem with the id you should just use the $index. I updated the codepen so it solves your problem and I'll come back at you to help you with the style of the checkbox(which is not the question initially).
http://codepen.io/anon/pen/dYMBqj?editors=101

You need to call componentHandler.upgradeElement(el) after adding the checkbox to the DOM. I'm not familiar with vue.js, so I can't suggest the specific code change required, but this article seems like it has the answer.

Related

Using .jquery .on() without an event

I have input elements that get appended to my HTML document that I need to get the value of. I understand that .on() should be used to get appended elements, but .on() expects an event to activate it, and I don't need an event.
Below is the code. #save_design is on a different part of the page. #fields_cnt is the parent that holds all my appended forms. .reg_field is the element I'm trying to get the value of. The first child works because that form is present when the document is loaded, or in other words, it is not appended. The other children all returns values undefined, or false depending on the input type and the logic I'm applying to it. This leads me to believe that .on() or something close to it should be used.
To clarify, I am trying to get the value of an appended input when #save_design is clicked.
$('#save_design').click( function() {
group_text[form_count] = $('#fields_cnt .field_group:nth-child(' + child + ') .reg_field').val();
I have tried replacing the originating click event as so. It has not worked.
$('body').on('click', '#save_design', function(){
I have tried using .on() without an event or event object. It has also not worked.
$('body').on('', '', function(){
group_text[form_count] = $('#fields_cnt .field_group:nth-child(' + child + ') .reg_field').val();
});
I have found a plugin that should work.
JQuery selecting dynamically generated html without adding event (with live)
This is not ideal, because as stated in the github readme, it is being rewritten. Also, the SO answer is 3 years old now, so it may no longer be the correct answer.
https://github.com/brandonaaron/livequery
I'd like to find a more direct solution. Is there a way to do this natively in jQuery? Is there a way to use .on() without an event, and if so, what's the appropriate syntax?
UPDATE: Clarification: The input fields get appended when an add field button is pressed. Their values change after they are appended. I would prefer not to rerecord the value of an input, every time it is altered.
UPDATE Here is the HTML structure to give a better idea of how I'm defining child.
<div id="fields_cnt">
<div id="field_group_1" class="field_group form-group">
<input placeholder="Field" class="reg_field form-control" />
</div>
<!-- This is appended by jQuery. There may be multiple of these -->
<div id="field_group_2" class="field_group form-group">
<input placeholder="Field" class="reg_field form-control" />
</div>
</div>
I have found a great solution to my problem. It takes a different approach on selecting the element, but ultimately works and results in drier code.
Here, I use each, to grab each instance of the appended element I am trying to select. This returns the desired value.
$('.reg_field').each( function() {
group_text[form_count] = $(this).val();
form_count++;
});
I suspect the issue was my previous selector was unable to use $(this), which seems to work in more cases for appended elements. Another possibility that was brought up in the comments was the use of nth-child in the middle of a selection. I am not sure on these points, and would appreciate a better explanation. Hopefully this will help for someone who faces the same issue. Also, I appreciate the help on getting me to focus on the selection rather than the binding.

Issue while accessing element by dojo.byId dojo 1.8

I am trying to access a div element text by using dojo.byId but it is returning the value which is set at first time the value is selected.It is somehow binding the value initially selected to the id of div and hence returning the same value even after I change the value to some other value.
var startDateLabel = dojo.byId("startDateLabel");
<label class="secondaryColor bold75Font floatRight" id="startDateLabel">${startDate} </label>
I tried to use registry.ById but since it is in a widget that is created more than once , it gives "id already registered error".For removing that , I also used destroyRecursive method but that also doesn't work.
Earlier, I used the id of container in which the widget is loaded and traversed to the children hierarchy to get the label value and it worked fine. but the child traversal code made it a bit messy.Something like
var startDateCont = registry.byId("startDateContainer");
var startDateLabel = startDateCont.domNode.children[1].children[1].children[1].innerHTML;
Is there any other way in dojo to achive this????
If you're using this inside a widget you should not even use IDs (or at least use generated IDs). The best way to get a reference to a DOM node while using a widget is by using attach points. An example, consider the following HTML:
<label class="secondaryColor bold75Font floatRight" data-dojo-attach-point="startDateLabel">${startDate} </label>
As you can see I introduced an attribtue called data-dojo-attach-point which allows me to give a name to the label (similar to an ID).
Then inside the widget you can now easily get a reference to that DOM node by using:
this.startDateLabel;
Just some extra information, you can also define events in a similar way by using data-dojo-attach-event. Make sure to read this part of the Writing your own widget article.

Knockout.js multiple observable arrays not working?

Evening all.
I have been experimenting for the first time with Knockout.js and i am having issues with multiple knockout arrays in the same page.
http://jsfiddle.net/573Vc/
e.g.
var linksBinding = ko.applyBindings(new LinksViewModel());
var tasksBinding = ko.applyBindings(new TasksViewModel());
The above jsfiddle shows how the top "Tasks" are working great and if i remove all code / html that relate to tasks then the links will also work fine on their own. When i add them to the same page however the second one starts to fail. Can anyone shed any light? It complains that parameters are not defined when i know they are?
Thanks
I'm not a knockout expert. However, I believe that you can only bind once to a specific element. The document is the default element if none is specified in the binding. So, in your case, you're doing two bindings (i.e applyBindings()) but you don't specify an element so only one binding takes place.
Check out this fiddle (note, I added jquery so that I could use jquery to access the element.)
I simply added an id to each div and updated the bindings to specifically bind to each element.
<div id="tasks" class='app-panel-section' data-bind="foreach: taskCategories">
...
var tasksBinding = ko.applyBindings(new TasksViewModel(),$("#tasks")[0]);

Jquery remove function follow up

I submitted this question last week:
chrome not working with jquery remove
and was able to resolve it (stupidity on my part really), however my example was very simple. Currently I'm trying to use .remove to eliminate a complete div from a page before sending an array of inputs to an ajax function. However, I am not able to get .remove to work at all.
Here's my latest try:
http://jsfiddle.net/CJ2r9/2/
I get function not defined on the jsfiddle on multiple browsers. On my application I get absolutely no errors, but nothing works either.
I'm relatively new to javascript scopes, so if the problem is scope-wise then please let me know how I'm screwing up.
I have also tried using the .on jquery function, but it's a bit more confusing considering my div ids are dynamically loaded from the server (jstl, spring MVC, etc). If that's a solution please let me know how I can get on the right track.
Thank you!
The two problems in your jsFiddle are:
Scope: removeElem is not in global scope, since you left the default configuration option to execute the code on DOM ready. You can change it to "no wrap" to make the funciton global.
The elements you want to remove don't exist. The div elements have IDs like "removeXXXp" and in your event handlers you pass "removeXXXs".
Here is an other, simpler solution (in my opinion) for element removal. Given your markup:
<div class="scheduleSet" id="remove315p">
<!-- ... -->
Remove
</div>
You can use .on like so:
$('.schduleSet a.optionHide').on('click', function() {
// traverses up the DOM tree and finds the enclosing .schduleSet element
$(this).closest('.scheduleSet').remove();
});
You don't even need IDs at all.
I made a simple fiddle, the inline onclick doesn't see the function defined in javascript so I get a ReferenceError: myRemove is not defined.
By adding the listener in js, .remove() works fine.
Sorry I don't know what causes the difference in behavior though.
Test it out: http://jsfiddle.net/xTv5M/1/
// HTML5
<div id="removeme">foo bar</div>
<button onclick="myRemove('removeme')">Go</button><br>
<div id="removeMe2">foo bar</div>
<button id="go2">Go Again</button>
// js
function myRemove(name){
$('#'+name).remove()
};
$('#go2').click(function(){ myRemove('removeMe2') });
I see that you are already using jquery. Why dont you do it this way:
<div id="foo">This needs to be removed</div>
Remove
function removeElem(element){
$('#'+element).remove();
}
$(function(){
$("#remove").click(function(){
removeElem($(this).data('remove'));
});
})
Fiddle here: http://jsfiddle.net/vLgpk/
They way this works is, using data-remove (can be anything like data-xyz btw), binds the remove link with the div. You can then read this binding later when remove is clicked.
If you are new to jQuery, and wondering what data-remove is, its just custom attribute that you can add to you code which can be later retrieved using the data() call on the element. Many great frameworks like Bootstrap use this approach.
Advantage of using this approach in my opinion is you can have the remove links anywhere in your UI and they don't need to be related structurally to your divs by siting inside them.

Add a listener to an element that is dynamically added

I have a javascript/jQuery page where I'm using Twitter Bootstrap's typeahead. There are two separate places in the javascript where I add elements that I would like to be typeaheads. Without asking for subjective answers, what's a good way for me to register the inputs as typeaheads dynamically? Give them all different ID's and register every time I add them? Is there any magic that can be done with .on()?
You can use jQuery delegation to do that. For example:
$("#element-that-will-contain-typeaheads").on("DOMNodeInserted", function () {
$(this).find(".typeahead").typeahead();
});
the most simplest way, that will work for typeahead, datepicker etc
First you need to understand how you are adding input elements that you want to apply bootstrap typeahead
to add elements try to achieve something like below:
//add this in your add button click handler
$tinput = $('<input type="text" name="bootstrap" class="typeahead"/>');
//apply bootstrap typeahead
$tinput.typeahead();
this way it will work, I thought sharing here would help others :)

Categories