Limit the input in Fieldset - javascript

I am trying to create a section of my webstore where the customer can 'build' their own bundle and choose any combination of 5 items.
I have a set of buttons which, when clicked, add their value to a Fieldset along with a button to remove it in case they misclicked or changed their mind.
All the components work fine, but I don't know how to limit the Fieldset to only five items. Is there a way to either count the lines, then stop accepting input
after five or look for 'Remove' five times?
I'm still fairly new to coding and not too sure what is possible.
This input will end up being submitted in a form.
Here is my Fiddle and below is my Javascript code which i have tried for it :
$(document).ready(function () {
$(".buttons").click(function () {
var intId = $().length + 1;
var item = $(this).html();
var fieldWrapper = $("<div class=\"fieldwrapper\" id=\"field" + intId + "\"/>");
var removeButton = $("<input type=\"button\" class=\"remove\" value=\"Remove\" />");
removeButton.click(function () {
$(this).parent().remove();
});
fieldWrapper.append(size);
fieldWrapper.append(removeButton);
$("#buildyourkit").append(fieldWrapper);
});
});

This will give you the current quantity of elements added to the . Just make sure that there is still room for another before appending a new one.
$("fieldset .fieldwrapper").length
I've forked your fiddle. Just look at the console while adding new items to the fieldset.

You can have a global variable which will count up and disable all buttons if over 5 every time you add a field, and down and enable all buttons every time you remove a field.
Also, it is a bit nicer to just set a live handler listening for any remove buttons, rather than make a new function and bind a new listener for each button, so I demonstrated; but it is not obligatory (your way works, too, given it's just 5 elements).
$(document).ready(function () {
var buttonMaxID = 0;
var buttonCount = 0;
$('$buildyourkit').on('click', '.remove', function () {
$(this).parent().remove();
if (buttonCount-- >= 5) {
$('.buttons').prop('disabled', false);
}
});
$(".buttons").click(function () {
if (++buttonCount >= 5) {
$('.buttons').prop('disabled', true);
}
var item = $(this).html();
var fieldWrapper = $("<div class=\"fieldwrapper\" id=\"field" + (buttonMaxId++) + "\"/>");
var removeButton = $("<input type=\"button\" class=\"remove\" value=\"Remove\" />");
fieldWrapper.append(size);
fieldWrapper.append(removeButton);
$("#buildyourkit").append(fieldWrapper);
});
});

What I propose is designing a manager class to maintain all functions/methods that must interact with the UI. This allows you to define your data set in one place, and keep the UI binds in one place. By doing so, you set yourself up with a cleaner code base, easy refactoring, and quickly make code modifications. Also, you get all this goodness without any global variables, another great bonus.
The code does look like its larger, but once you understand the simplicity of the manager you will see the possibilities I outlined above.
$(document).ready(function () {
//Create a new Kit Manager
var kitManager = new KitManager();
$(".buttons").click(function () {
kitManager.add(this);
});
$(".report").click(function () {
kitManager.getKit();
});
});
function KitManager()
{
//Static amount of items to return
var MAX_ITEMS = 5;
//Where the items should be visually displayed on the UI
var kitLegend = $("#buildyourkit");
//Internal array for storing the items added
var items = []
function add(element)
{
if(items.length < MAX_ITEMS)
{
var itemNumber = items.length + 1;
var item = $(element).html();
var fieldWrapper = $("<div class=\"fieldwrapper\" id=\"field" + itemNumber + "\"/>");
var removeButton = $("<input type=\"button\" class=\"remove\" value=\"Remove\" />");
//Add item to the array collection
items.push(item);
//Bind a remove function to the newly created button
removeButton.click(function () {
kitLegend[0].removeChild(fieldWrapper[0]);
items.splice(itemNumber, 1);
});
//Append UI components to container
fieldWrapper.append(item).append(removeButton);
//Append to main legend
kitLegend.append(fieldWrapper);
}
else
{
//Simple alert to user
alert('You\'ve Reached The Maximum Number of Items');
}
}
//Simple function for demonstration of a reporting feature
//or potential method for returning the stored items
function getKit()
{
for(var i=0,length=items.length;i <length;i++)
{
console.log(items[i]);
}
}
//Expose public method call
return {
add:add,
getKit: getKit
};
}
http://jsfiddle.net/x97S5/
I hope you find the solution acceptable, and if you have any further questions please ask.
For more information on the solution and technique proposed take a look at Key Principles of Maintainable JavaScript

Related

Generating HTML toggle buttons with JavaScript and initializing them

I have a div:
<div id="div1">
</div>
And I'm trying to generate "toggle" buttons (http://www.bootstraptoggle.com/) with JavaScript:
<script>
var count = 1;
function foo() {
var newButton = "<input type=\"checkbox\" id=\"" + count + "\" checked data-toggle=\"toggle\"><br>";
document.getElementById('div1').innerHTML += newButton;
$('#' + count).bootstrapToggle();
// also tried re-initializing the first created button, this won't work either..
//$('#1').bootstrapToggle();
count = count + 1;
}
setInterval(foo, 4000);
</script>
This creates the buttons just fine, but those have to be initialized first by calling.
$('#1').bootstrapToggle();
The problem is, that when I have generated the first button and generate the second, the first one stops working. I have also tried to re-initialize the first button in the same div, but that won't work either.
Please, if there's a better way to do this I'd be glad to receive some help (or better, example code) on how to do this. The thing is that I cannot do this other way, because I'm generating these from JSON input.
As Rajesh says, the +=innerHTML is causing problems.
This will work:
<div id="container"></div>
var count = 1;
function createButton() {
var newButton = "<input type='checkbox' id='" + count + "' checked data-toggle='toggle'><br>";
$('#container').append(newButton);
$('#' + count).bootstrapToggle();
count = count + 1;
}
setInterval(createButton, 1000);
Edit: You can also tidy things up a little to lose the ugly count global:
function createButton() {
$('<input/>', {
type: 'checkbox',
checked: 'checked',
data: {
toggle: 'toggle'
}
})
.appendTo('#container')
.bootstrapToggle();
}
setInterval(createButton, 1000);

Dynamically Moving Through Hidden Tables With jQuery

I'm having issues moving through a sequence of Hidden Divs that will eventually turn into Tables on another page that I am working on and the issue that I am running into is that the jQuery Javascript code does not seem to be responding to calls.
My JS Fiddle Example:
http://jsfiddle.net/qwertycody/QUprb/3/
My Actual Applied Work:
http://www.voyagersclan.com/scripts/pokemon/poke_pc.php
<script type="text/javascript" src="jquery.js"></script>
<script>
var currentID = 1;
$(function() {
$('#left').on('click', function(){
var currentDiv = '#' + currentID;
$('currentDiv').hide(500);
currentID = currentID - 1;
currentDiv = '#' + currentID;
$('currentDiv').show(500);
})
});
$(function() {
$('#right').on('click', function(){
var currentDiv = '#' + currentID;
$('currentDiv').hide(500);
currentID = currentID + 1;
currentDiv = '#' + currentID;
$('currentDiv').show(500);
})
});
</script>
Above is a code sample of my Javascript that doesn't seem to work correctly.
The overall goal of this is to be able to move through dynamically generated Tables with Individually Assigned Divs that can freely be Shown and Hidden at the press of a button.
Your answer is very close! The problem is that your selector is using a string, instead of the variable you intialized!
var currentDiv = '#' + currentID;
$(currentDiv).hide(500); // works!
$('currentDiv').hide(500); // gets an element of type "currentDiv"
Look at this updated JSFiddle.
I also added some bounds checks into your event handlers. This way you can only scroll through the available tables (1-4).

How to count dynamically created divs

I'm trying to write a form builder where users can generate a signup form. I need to limit the amount of items that the user can create however they also need to delete the items.
Originally I had
var limit = 5;
var counter = 0;
if (counter == limit) {
However when the user deleted items the counter remained the same and so they couldnt replace the deleted form element with a new item. So what I want to do is count how many items are currently active. I tried to do this by giving each new element a class (.kid) and then counting the amount of divs with that class but it didnt work.
Could anyone point me in the right direction? This is what I have so far however it doesn't work.
var limit = 6;
var num = $('.kid').length;
function addAllInputs(divName, inputType){
if (num == limit) {
alert("You have all ready added 6 form items");
}
else {
var newdiv = document.createElement('div');
newdiv.setAttribute('id', 'child' + (counter + 1));
newdiv.setAttribute('class', 'kid' );
Cheers all!
You need to capture the current counter in a closure. Decrease the counter when the user deletes an item and increase it after an item is created. Your code sample doesn't reveal how you handle the deletion, but I'll try to illustrate what I mean with a small code snippet:
$(document).ready(function () {
var limit = 5;
var counter = $('.kid').length;
$('#triggers_delete').click(function () {
/* delete the item */
counter--;
});
$('#triggers_creation').click(function () {
if (counter == limit) {
alert('Limit reached');
return false;
}
/* somehow determine divName and inputType
and create the element */
addAllInputs(divName, inputType);
counter++;
});
});
function addAllInputs(divName, inputType) {
/* just create the item here */
}
Is there any reason an approach like this won't work? Every time you go to add a new DIV, the length of the current collection is examined to see if it meets or exceeds the limit. Of course, you may need to refine the scope of your selector if there could be other DIVs of the form with the same class ID.
var limit = 6;
function addAllInputs(divName, inputType){
if ( $('.kid').length >= limit ) {
alert("You have all ready added 6 form items");
}
else {
var newdiv = document.createElement('div');
newdiv.setAttribute('id', 'child' + (counter + 1));
newdiv.setAttribute('class', 'kid' );
}
Edit: Just a note, I am assuming that you are either removing the deleted items from the DOM or differentiating them from active items with a different class or attribute. Otherwise, the approach I suggested will return a count that includes the deleted items as well.
The only real issue is that your num variable is being defined outside of the function. It will get the number of .kid elements at the time the page loads and will not update. Simply move this line inside the function:
var limit = 6;
function addAllInputs(divName, inputType){
var num = $('.kid').length;
...
Try this
var limit = 6;
function addAllInputs(divName, inputType){
if ($('.kid').length == limit) {
alert("You have all ready added 6 form items");
}
else {
var newdiv = $('div', { 'id': 'child' + (counter + 1), 'class': 'kid' } );
$("inputContainerSelector").append(newdiv);
}

JQuery Chained/Cascading Dropdown events

I am currently attempting to set up a set of chained selects using the Flexbox Jquery plugin (this is not specifically designed for chaining, but can be used for that).
I have the chaining working if I set everything explicitly, but I am trying to dry my code up and make it more understandable. As such, I have come up with the code below.
All boxes currently load initially, and make their queries. The problem I am having is that when I iterate through the menus (as below), I lose the onSelect functionality - it only fires for the last menu I loaded.
My understanding was that since I am using a different JQuery selector each time - $('#' + fbMenu.divId) - it would not matter that I then set the onSelect behavior for another menu, but evidently this is not the case. Am I somehow overwriting the binding each time I am loading a box?
Hopefully I don't have to specify the onSelect functionality for each dropdown, as there could be a large number of them.
Many thanks for any assistance you can provide!
$(document).ready(function() {
// Create the variables for data objects
var vehicleMakeFb = new Object();
var vehicleModelFb = new Object();
var vehicleTrimFb = new Object();
// Set up each menu with the divId, jsonUrl and the chlid menus that will be updated on select
vehicleMakeFb.divId = 'vehicle_vehicleMake_input';
vehicleMakeFb.jsonUrl = '/vehicles/getmakes';
vehicleMakeFb.children = [vehicleModelFb];
vehicleModelFb.divId = 'vehicle_vehicleModel_input';
vehicleModelFb.jsonUrl = '/vehicles/getmodels';
vehicleModelFb.children = [vehicleTrimFb];
vehicleTrimFb.divId = 'vehicle_vehicleTrim_input';
vehicleTrimFb.jsonUrl = '/vehicles/gettrims';
vehicleTrimFb.children = [];
// Create an array of all menu objects so that they can be iterated through
var allMenus = [vehicleMakeFb,vehicleModelFb,vehicleTrimFb];
// Create the parent menu
for (var i = 0; i < allMenus.length; i++) {
var fbMenu = allMenus[i];
alert(fbMenu.divId);
$('#' + fbMenu.divId).flexbox(fbMenu.jsonUrl + '.json', {
// Update the child menu(s), based on the selection of the first menu
onSelect: function() {
for (var i = 0; i < fbMenu.children.length; i++) {
var fbChild = fbMenu.children[i];
var hiddendiv = document.getElementById(fbMenu.divId + '_hidden');
var jsonurl1 = fbChild.jsonUrl + '/' + hiddendiv.getAttribute('value') + '.json';
alert(jsonurl1);
$('#' + fbChild.divId).flexbox(jsonurl1);
}
}
});
}
});
If you put all the information on the elements them selves i think you will have better results. Although I've been known to be wrong, I think the context of the select functions are getting mixed up.
instead of setting up each menu as an object try:
$(document).ready(function() {
var setupdiv = (function(divId, jsonUrl, children)
{
jQuery('#' + divId)
.data("jsonurl", jsonUrl)
.data("children", children.join(",#"));
   
// Create the parent menu
jQuery('#' + divId).flexbox(jsonUrl + '.json',
{  
// Update the child menu(s), based on the selection of the first menu
onSelect: function()
{  
var children = jQuery(this).data("children");
var jsonUrl = jQuery(this).data("jsonurl");
if(children)
{
children = jQuery('#' + children);
alert('children was true');
}
else
{
children = jQuery();
alert('children was false');
}
var hiddendiv = jQuery('#' + this.id + '_hidden');
children.each(function()
{
var childJsonUrl = jsonUrl + '/' + hiddendiv.val() + '.json';
alert(childJsonUrl);
$(this).flexbox(childJsonUrl);  
});
}
});
});
setupdiv('vehicle_vehicleMake_input', '/vehicles/getmakes', ['vehicle_vehicleModel_input']);
setupdiv('vehicle_vehicleModel_input', '/vehicles/getmodels', ['vehicle_vehicleTrim_input']);
setupdiv('vehicle_vehicleTrim_input', '/vehicles/gettrims', []);
});
DISCLAIMER
I'm known for my spelling mistakes. Please spellcheck before using this code ;)
Update
I've changed the first two lines of code and I've normalized the indenting as there were a mix of tabs and spaces. Should be easier to read now.

Javascript running twice

I have to develop a small application for school and I first designed in photoshop a bit and "converted" it into html. That went all fine. I created a custom dropdown with javascript and it worked smoothly. I've just tried implementing CodeIgniter into the design but the javascript started running twice.
I've tried comparing the code of the plain html version with the codeigniter result but I can't seem to find any difference.
Can any of you maybe help me?
Here's the CodeIgniter result:
http://intellia.itforit.net/index.htm
As asked by Krof Drakula here are the most important pieces of code:
The actual jquery plugin: (styleForm.js)
;(function($){
$.fn.styleForm = function() {
var form = this;
/* Select */
$('select', this).each(function(){
var div = '<div class="styledSelect"><ul>';
var first = false;
$('option', this).each(function(){
var cssclass = "";
if(!first) {
first = true;
cssclass = 'class="first"'
}
div += '<li ' + cssclass + ' id="' + $(this).attr("value") + '">' + $(this).text() + '</li>';
});
div += '</ul></div>';
$(this).hide();
$(this).after(div);
});
$('.styledSelect ul').toggle(function(){
$('li:not(.first)', this).show("fast");
}, function(){
$('li:not(.first)', this).hide("fast");
});
$('.styledSelect ul li:not(.first):not(.selected)').click(function(){
var id = $(this).attr('id');
var content = $(this).text();
$('.styledSelect ul li.first').attr('id', id).text(content);
$('.styledSelect ul li').css({'font-weight': 'normal'});
$(this).css({'font-weight': 'bold'});
/* SELECT in Select form item */
var selected = $('select option[value="' + id + '"]:not(.first)', form).get(0);
selected.setAttribute("selected", "selected");
//$(form).submit();
});
};
})( jQuery );
And here's where it gets launched: (canvasDrawing.js)
$(document).ready(function(){
$('form').styleForm();
//Unimportant canvas stuff
});
Thanx in advance,
Duckness
The problem is that your canvasDrawing.js, in the "unimportant canvas stuff", causes a javascript error. If the canvas it describes actually exists, your styleForm stuff only runs once. So add this to your HTML:
<canvas id="floorplan"></canvas>
And magic will happen. Or, in your canvasDrawing file, add clause like this right after styleForm:
var canvas = document.getElementById('floorplan');
if (!canvas)
return;
I'm not actually all that clear why having an error in that function causes it to run twice, but it's definitely the problem. See it: your code + a canvas element = working.

Categories

Resources