I am learning to write a plugin for myself, but I got something odd in the code. I have a reset button, and when I click it, it runs as times as the number of input elements I have.
My code: jsbin, jsfiddle
HTML:
<div id="container">
<div id="createCSVWrap">
<fieldset>
<legend> Create the CVS File </legend>
<div class="dateWrap">
<label> 开始时间: </label>
<div style="float:right">
<input id="startTime" name="startTime" type="text" value="13:37:06" />
</div>
</div>
</fieldset>
</div>
<input id="f" name="fck" value="18:27:56" />
<input class="tt" name="tt" value="02:07:56" />
<input name="ok" class="ok" value="08:07:56" />
</div>
Javascript
$(document).ready(function() {
$('#startTime').timePicker();
$('#f').timePicker();
$('.tt').timePicker();
$('.ok').timePicker();
});
(function($) {
$.fn.timePicker = function(options) {
var defaults = {
setTimeFocus: 'hour'
}; //,originalTime :''
var options = $.extend(defaults, options);
if ($('#timePicker').length === 0) {
var timePickerBody = '<div id="timePicker" style="display:none;">' + '<div id="setTimeOption">' + ' RESET' + '</div></div>';
$("body").append(timePickerBody);
}
return this.each(function() {
var o = options;
$(this).focus(function() {
_input = $(this); // ONLY put here can change value of each input field
originalTime = '';
//originalTime = {} ;
intial();
});
function intial() {
showSetTime();
setTimePickerPosition();
$('#timeReset ').click(resetTime);
}
function showSetTime() {
$('#timePicker').show();
}
function hiddenSetTime() {
$('#timePicker').hide();
}
function setTimePickerPosition() {
var _inputPosition = _input.offset();
var _timePickerPosition = [_inputPosition.left, _inputPosition.top + _input.height()];
var _timePickerPositionLeft = _timePickerPosition[0],
_timePickerPositionTop = _timePickerPosition[1];
$('#timePicker').css({
'left': _timePickerPositionLeft + 'px',
'top': _timePickerPositionTop + 'px'
});
}
time = 1;
function resetTime(event) {
event.preventDefault();
time++;
alert(time)
}
$(this).click(function(e) {
e.stopPropagation();
});
$('#timePicker').click(function(e) {
e.stopPropagation();
});
$(document).click(function() {
hiddenSetTime();
});
});
// ending return this
};
})(jQuery);
CSS:
#timePicker
{
position:absolute;
width:185px;
padding:10px;
margin-top:5px;
background:#F3F3F3;
border:1px solid #999;
}
I think I see the problem here. It's to do with this bit of code:
$(this).focus(function() {
_input = $(this);
originalTime = '';
intial();
});
function intial() {
showSetTime();
setTimePickerPosition();
$('#timeReset').click(resetTime);
}
This basically means that every time the user focuses onto the textbox another click handler will get attached to the "Reset" button, thus the same event firing multiple times.
What you need to do is the unbind the old event and reattach a new one, with the unbind event.
$('#timeReset').unbind('click').click(resetTime);
See it working here: http://www.jsfiddle.net/Sc6QB/1/
Related
I have a Two div when i click on the first div checkbox i want to use second div checkbox value.
var NewData = '<div class="divClassOne">
<input type="checkbox" class="chkremCFAllLevel1" value="HelloOne" name="chkOne"
id="check1" data-markerAllLevel1="12"></div>';
$("#sectionlistNew").append(NewData);
var NewDataTwo = '<div class="divClassTwo">
<input type="checkbox" class="chkremCFAllLevel2" value="HelloTwo" name="chkTwo"
id="check2" data-markerAllLevel2="12"></div>';
$("#sectionlistNewTwo").append(NewDataTwo);
$("#sectionlistNew").on('click', '.chkremCFAllLevel1', function () {
marker_refAllLevel1 = $(this).attr('data-markerAllLevel1');
console.log(marker_refAllLevel1);
});
When i click i want to compare data-markerAllLevel1 and data-markerAllLevel2 value.
Solution
$("#sectionlistNew").on('click', '.chkremCFAllLevel1', function () {
checkedvalueAllCheckBoxLevel1 = [];
marker_refAllLevel1 = $(this).attr('data-markerAllLevel1');
console.log(marker_refAllLevel1);
$("input[name=chkRolesALLLevel2]").each(function () {
if ($(this).attr("data-markerCheckBoxAllLevel2") == marker_refAllLevel1) {
console.log($(this).attr("data-markerCheckBoxAllLevel2"));
$('input[name="chkRolesALLLevel2"][data-markerCheckBoxAllLevel2="' + marker_refAllLevel1 + '"]').attr('disabled', false);
}
});
});
Code:
var NewData = '<div class="divClassOne"> <input type="checkbox" class="chkremCFAllLevel1" value="HelloOne" name="chkOne" id="check1" data-markerAllLevel1="12"></div>';
$("#sectionlistNew").append(NewData);
var NewDataTwo = '<div class="divClassTwo"> <input type="checkbox" class="chkremCFAllLevel2" value="HelloTwo" name="chkTwo" id="check2" data-markerAllLevel2="12"></div>';
$("#sectionlistNewTwo").append(NewDataTwo);
$("#sectionlistNew").on('click', '.chkremCFAllLevel1', function() {
marker_refAllLevel1 = $(this).attr('data-markerAllLevel1');
marker_refAllLevel2 = $('#check2').attr('data-markerAllLevel2');;
if (marker_refAllLevel1 == marker_refAllLevel1) {
console.log('Its both are same' + marker_refAllLevel1 + '=' + marker_refAllLevel2);
} else {
console.log('Its both are not same');
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="sectionlistNew"></div>
<div id="sectionlistNewTwo"></div>
You need to explain more, what are you trying to do.
HTML:
<input type="checkbox" class="chkremCFAllLevel1" value="HelloOne" name="chkOne" id="check1" data-markeralllevel1="12">
<input type="checkbox" class="chkremCFAllLevel2" value="HelloTwo" name="chkTwo" id="check2" data-markeralllevel2="12">
Jquery:
$(document).ready(function() {
$("input[data-markerAllLevel1]").change(function () {
let markerAllLevel1 = $(this).data('markeralllevel1')
let markerAllLevel2 = $('[data-markeralllevel2]').data('markeralllevel2')
console.log(`${markerAllLevel1} == ${markerAllLevel2}`)
if(markerAllLevel1 == markerAllLevel2){ /* compare here whatever you need (not sure what you mean) */
if($(this).is(':checked')){
$('input[data-markeralllevel2]').prop('checked', true);
} else {
$('input[data-markeralllevel2]').prop('checked', false);
}
}
/* if you need to set value to another one, use this */
$('input[data-markeralllevel2]').val($(this).val())
console.log($('input[data-markeralllevel2]').val())
});
$("input[data-markeralllevel2]").change(function () {
let markerAllLevel1 = $('input[data-markeralllevel1]').data('markeralllevel1')
let markerAllLevel2 = $(this).data('markeralllevel2')
console.log(`${markerAllLevel1} == ${markerAllLevel2}`)
if(markerAllLevel1 == markerAllLevel2){ /* compare here whatever you need (not sure what you mean) */
if($(this).is(':checked')){
$('input[data-markeralllevel1]').prop('checked', true);
} else {
$('input[data-markeralllevel1]').prop('checked', false);
}
}
/* if you need to set value to another one, use this */
$('input[data-markeralllevel1]').val($(this).val())
console.log($('input[data-markeralllevel1]').val())
});
});
So I have been messing around with dynamic input fields and everything is working great. The only issue I'm having is stopping the first input_line from being deleted.
So pretty much every input_line (refer to my fiddle for exmaple) should be able to be removed except the first one, that one should always stay.
Illustration:
Any suggestions how I can achieve this?
HTML:
<form action="javascript:void(0);" method="POST" autocomplete="off">
<button class="add">Add Field</button>
<div class='input_line'>
<input type="text" name="input_0" placeholder="Input1"><input type="button" class="duplicate" value="duplicate"><input type="button" class="remove" value="remove">
</div>
</form>
jQuery:
$(document).ready(function () {
'use strict';
var input = 1,
blank_line = $('.input_line');
$('.add').click(function () {
var newElement = blank_line.clone(true).hide();
$('form').append(newElement);
$(newElement).slideDown();
});
$('form').on('click', '.duplicate', function () {
$(this).parent().clone().hide().insertAfter($(this).parent().after()).slideDown();
$('.input_line').last().before($('.add'));
input = input + 1;
});
$('form').on('click', '.remove', function () {
$(this).parent().slideUp(function () {
$(this).remove();
});
$('.input_line').last().before($('.add'));
input = input - 1;
});
});
JSFiddle
Any help would be greatly appreciated!
Hide the remove when there's one row, else show it:
http://jsfiddle.net/gqgaswdy/23/
$(document).ready(function () {
'use strict';
var input = 1,
blank_line = $('.input_line');
var removing = false;
$('.remove').hide();
$('.add').click(function () {
var newElement = blank_line.clone(true).hide();
$('form').append(newElement);
$(newElement).slideDown();
$('.remove').show();
});
$('form').on('click', '.duplicate', function () {
$(this).parent().clone().hide().insertAfter($(this).parent().after()).slideDown();
$('.input_line').last().before($('.add'));
$('.remove').show();
input = input + 1;
});
$('form').on('click', '.remove', function () {
if (removing) {
return;
} else {
if ($('.input_line').length <= 2) $('.remove').hide();
$(this).parent().slideUp(function () {
$(this).remove();
removing = false;
});
$('.input_line').last().before($('.add'));
input = input - 1;
}
removing = true;
});
});
Just would like to show you how easy it is to create such behavior in frameworks actually intended for databinding (which jquery is not, so you have to write a lot of additional/unnecessary logic) with example of knockout.js
Demo
<div data-bind="foreach: rows">
<div>
<input type="text" data-bind="value: $data.name">
<button data-bind="click: $root.duplicate">Duplicate</button>
<button data-bind="click: $root.remove, enable: $root.rows().length > 1">Remove</button>
</div>
</div>
<button id="button" data-bind="click: addRow">add Row</button>
var row = function(name) {
this.name = ko.observable(name);
};
function TableModel() {
var self = this;
self.rows = ko.observableArray([]);
self.addRow = function() {
self.rows.push( new row('') );
};
self.duplicate = function(a) {
self.rows.push( new row(a.name()) );
};
self.remove = function(a) {
self.rows.remove(a);
};
}
ko.applyBindings(new TableModel());
Maybe add new function like this:
function HideRemoveButton(){
if($('.input_line').length <= 1){
$('.remove').hide()
}
else{
$('.remove').show()
}
}
I am creating a system where a user can preview the title and steps of a recipe, i have created a dynamic form so the user can add more steps, the preview works with the title and first step however it seems that i can't get it to work on the second, third, fourth step. Can anyone help me? Any help would be greatly appreciated!
http://jsfiddle.net/uKgG2/
Jquery
var commentNode = $('#lp-step'),
nameNode = $('#lp-name');
$('input, textarea').bind('blur keyup', function () {
commentNode.html($('textarea[name="step_detail[]"]').val().replace(/\n/g, '<br />'));
nameNode.text('Title: ' + $('input[name="name"]').val());
});
var addDiv1 = $('#addStep');
var i = $('#addStep p').size() + 1;
$('#addNewStep').on('click', function () {
$('<p> <textarea id="step_' + i + '" name="step_detail[]"> </textarea>Remove </p>').appendTo(addDiv1);
i++;
return false;
});
$(document).on('click', '.remNew1', function () {
if (i > 2) {
$(this).parents('p').remove();
i--;
}
return false;
});
HTML
<label for="name">Enter recipe name:</label>
<input type="text" name="name">
<br />
<h1>Method</h1>
<div id="addStep">
<p>
<textarea id="step_1" name="step_detail[]"></textarea>
Add
</p>
</div>
<br />
<button type="submit">
Save on xml
</button>
</form>
<div id="live-preview-display">
<div id="lp-name"> </div>
<div id="lp-step"> </div>
</div>
You should bind the keyup or blur event to all the new textareas which are created with add button or link whatever.
Improved
try this :
$('#addStep').on('keyup', 'textarea', function () {
step_id = $(this).attr('id');
step_text = $('#' + step_id).val();
if($('.'+step_id).length > 0) {
$('.'+step_id).text(step_text);
return;
}
p = document.createElement('p');
p.className = step_id;
$(p).appendTo(commentNode);
$(p).text(step_text);
});
it worked! I saved it to fiddle too. you should just update the recipe name and clean this as I said i't very hacky just have to improve it.good luck. http://jsfiddle.net/uKgG2/3/
I have a javascript function which is designed to add and remove additional input field to a div.
In a specific case, I could specify the div to which I would like the fields to be added when the function is called.
However, I want to have multiple buttons associated with multiple corresponding divs on one page which could call the function to add a field to that div.
The function:
$(function() {
var scntDiv = $('#DIV');
var i = $('#DIV p').size() + 1;
$('.addField').on('click', function() {
$('<p><input type="text" id="field_' + i +'" size="20" name="field_' + i +'" value="" /> Remove</p>').appendTo(scntDiv);
i++;
return false;
});
$('.remField').on('click', function() {
if( i > 2 ) {
$(this).parents('p').remove();
i--;
}
return false;
});
});
As you can see the add field button listens for a button with the class "addField" to be clicked.
I would like that click to pass the parameter for #DIV to be equal to the # of the parent div of that button, is that possible?
EDIT: Per request here is my markup (example of) with function (note ??? placeholders)
JsFiddle
Does this jsfiddle do the trick?
Html:
<div id="div">
<div>
<button type="button">
<span>Add Field</span>
</button>
</div>
<div>
<button type="button">
<span>Add Field</span>
</button>
</div>
<div>
<button type="button">
<span>Add Field</span>
</button>
</div>
</div>
JavaScript:
(function ($, undefined) {
'use strict';
var i;
i = 0;
function fieldMaker () {
i += 1;
return $('<p><input type="text" id="field_' + i +'" size="20" name="field_' + i +'" value="" /> Remove</p>');
}
$(function () {
$('#div').on({
click : function () {
$(this).closest('div').append(fieldMaker());
}
}, 'button');
$('#div').on({
click : function () {
$(this).closest('p').remove();
}
}, 'a');
});
}(jQuery));
You could store the information – where to add the input – at the button, for example using the HTML5 data-* attributes:
<p><button data-add-field-to=".fieldset-1">add field to .fieldset-1</button></p>
<fieldset class="fieldset-1"></fieldset>
JS:
jQuery( function() {
var i = 1; // your counter logic here
jQuery( '[data-add-field-to]').each( function() {
var $button = $( this );
$button.on( 'click', function( event ) {
var newFieldId = 'field_' + i,
target = jQuery( $button.attr( 'data-add-field-to' ) );
jQuery( '<input type="text" id="' + newFieldId +'" size="20" name="' + newFieldId +'" value="" />').appendTo( target );
i++;
return false;
} );
} );
} );
I will assume you have a mapping between the buttons (let's say button id) and the elements to add to:
var mapping = {
'#button1' : $('#receiver1'),
'#button2' : $('#receiver2'),
'#button3' : $('#receiver3')
}
One solution is to check which button the click event was triggered on:
$('.addField').on('click', function() {
$('<mycontent>').appendTo(mapping(this.id));
i++;
return false;
});
A more elegant solution is to create a function for each button:
Object.keys(mapping).forEach(function(key){
$(key).on('click', function() {
$('<mycontent>').appendTo(this);
i++;
return false;
}.bind(mapping[key])); // force this to be the receiver
});
I'm working on a project where I'd place an search box with a default set of results, over the layout using Prototype which is triggered from a click event.
When the output is set, that new page has it's own Javascript which is uses, to dynamically filter the results.
Now the new set of results do not work with the Javascript set previously.
How can I maintain a persistent event with calling new events each time?
Or is that what I am supposed to do.
Here is a bit of code which is loaded in 'loaded_page.php'
<script language="javascript">
var o = new Compass_Modal('add_button', 'history');
var placetabs = new Tabs('tabs', {
className: 'tab',
tabStyle: 'tab'
});
$$('.add_button').each(function(s, index){
$(s).observe('click', function(f) {
loadData();
});
});
function loadData() {
new Ajax.Request('/sponsors/search', {
onComplete: function(r) {
$('overlay').insert({
top:'<div id="search_table">'+r.responseText+'</div>'
});
}
})
}
</script>
Then in the included page which is inserted via javascript:
<div id="search_overlay">
<div id="form_box">
<img src="/images/closebox2.png" class="closebox" />
<form method="post" id="search_form" class="pageopt_left">
<input type="text" name="search_box" id="search_box" value="search" />
</form>
</div>
<div id="table_overlay">
<table class="sortable" id="nf_table" cellpadding="0" border="0" cellspacing="0">
<tr>
<th id="name_th">Name</th><th id="amount_th">Amount</th><th id="tax_letter_th">Tax Letter</th><th id="date_th">Date</th><th id="add_th">Add</th></tr>
<tr>
<td>Abramowitz Foundation (The Kenneth & Nira)</td><td><input type="text" name="amount" value="" id="amount_111" /></td><td><input type="checkbox" name="tax_letter" value="1" id="tax_letter_111" /></td><td><input type="text" name="date" value="" id="date_111" /></td><td><img src="/images/icons/add.png" title="add contact" /></td></tr>
... more rows
</table>
</div>
</div>
<script language="javascript">
var c = new Compass_Search('contacts', 'table_overlay');
c.set_url('/sponsors/sponsor_search');
$$('.add_button').each(function(s, index) {
$(s).observe('click', function(e) {
$(e).stop();
var params = $(s).href.split("/");
var userid = params[5];
var amount = 'amount_'+params[5];
var date = 'date_'+params[5];
var tax = 'tax_letter_'+params[5];
if(!Form.Element.present(amount) || !Form.Element.present(date)) {
alert('your amount or date field is empty ');
} else {
var add_params = {'amount':$F(amount), 'date':$F(date), 'tax':$F(tax), 'id':userid};
if(isNaN (add_params.amount)) {
alert('amount needs to be a number');
return false;
} else {
new Ajax.Request('/sponsors/add', {
method: 'post',
parameters: add_params,
onComplete: function(e) {
var post = e.responseText;
var line = 'amount_'+add_params.id;
$(line).up(1).remove();
}
})
}
}
});
});
this.close = $$('.closebox').each(function(s, index) {
$(s).observe('click', o.unloader.bindAsEventListener(this));
})
</script>
You'll notice in the inserted portion, a new Javascript which also, updated its own content with yet new observers. When the content gets updated, the observers do not work.
Use event delegation.
Besides making it possible to replace "observed" elements, this approach is also faster and more memory efficient.
document.observe('click', function(e){
var el = e.findElement('.add_button');
if (el) {
// stop event, optionally
e.stop();
// do stuff... `el` now references clicked element
loadData();
}
});
As you're calling Element#insert, I suppose String#evalScripts should be automatically called (as having looked in the implementation of those methods)
Maybe you can try to do some console.log()/alert() messages before the Element#observe calls, to see where it is going wrong. It may be because the Javascript is not evaluated at all, or that there is something wrong with your code or something like that.
As a tip: check the documentation on Array#invoke, with that method you can rewrite something like:
$$('.add_button').each(function(s, index){
$(s).observe('click', function(f) {
loadData();
});
});
into this:
$$('.add_button').invoke('observe', 'click', function(event){
loadData();
});
// $$('.add_button').invoke('observe', 'click', loadData);