Appending a new file upload button when the previous changes - javascript

I have a function that uses jQuery to add in an additional file upload button when a user adds a file. My problem is that I cannot seem to have it either add in proper format or add every time. My current function simply tries added the string directly:
jQuery(document).ready(function($) {
$(function() {
$("input:file").change(function(){
$("input:file").after("</td></tr><tr><td class=\"field_name span4\"><strong></strong></td><td class=\"field_option\"><input type=\"file\" name=\"pictures\">");
});
});
});
You can see a live version of this here: http://1ro.co/salem/?module=insert
The issue with the method shown above is it does not add the first two closing tags: </td></tr>.
I've tried methods such as setting $("input:file"); to a variable, however that doesn't set for every value after the first. For example:
var count = 0;
jQuery(document).ready(function($) {
$(function() {
var input = $("input:file");
input.change(function(){
input.after(input.get(count++));
});
});
});
However this doesn't append at all (in theory would probably append every element), and I cannot use .after() on input.get(count).
In simple terms, I'm looking to improve this and make it so it will append the a new file upload button, and not being formatted improperly. If possible, I would rather use method 2 but at the moment I would like for it to just work.

You'll need to re-add the handler to each new file input, so best to isolate that in a function:
var addfile = function() {
var newRow = $("<tr><td class=\"field_name span4\"><strong></strong></td>" +
"<td class=\"field_option\"><input type=\"file\" name=\"pictures\">").
insertAfter($(this).closest('tr'));
newRow.find('input:file').change(addfile);
};
$("input:file").change( addfile );

I just tried out your live demo and it is inserting something. But it only happens once of course as your event handler is bound only to the first object.
I would try your change function using something like the following:
$('input:file').change(function() {
$(this).closest('tr').after($(this).closest('tr').clone());
});
but your change handler will have to be rebuilt as well.

Related

How can I pass data to an element's change() method?

I wrote an app where multiple users can edit a database in realtime. I am using socket-io to keep all users' pages up to date with any changes to the database.
All input values broadcast a change.
Say I bind a function to an input's change event:
$(".input-field").change(function(ev) {
codeThatChangesOtherInputValuesOnMyPage1;
codeThatChangesOtherInputValuesOnMyPage2;
codeThatChangesOtherInputValuesOnMyPage3;
codeThatChangesOtherInputValuesOnMyPage4;
codeThatChangesOtherInputValuesOnMyPage5;
codeThatChangesOtherInputValuesOnMyPage6;
codeThatChangesOtherInputValuesOnMyPage7;
codeThatChangesOtherInputValuesOnMyPage8;
var tableColumn = $(ev.target).attr('table-col');
var newFieldValue = $(ev.target).val()
broadcastChange(tableColumn, newFieldValue); // this is pseudo code for a socket-io emit()
});
socket.on('runThisWhenReceivingBroadcastFromServer', function(response) {
// response.data has the input element id of element I should update.
// Get the input field i should update
var theInputField = getInputField(response.data)
$(theInputField).val(getNewInputValue(response.data))
$(theInputField).change();
// I call change because I want all my code in the input's change function to run, except for the last line.
});
I have already fixed this problem, but I am repeating myself by just copying all my code from on change function and pasting it in the broadcast receiving and then just omitting the broadcastChange line. But i want to follow DRY (Don't Repeat Yourself).
Also codeThatChangesOtherInputValuesOnMyPage1; is just that, code. Its tons of code. How would you go about restructuring the code?
My first thought was to do something like this (pseudo code):
$(".input-field").change(function(ev) {
codeThatChangesOtherInputValuesOnMyPage1;
codeThatChangesOtherInputValuesOnMyPage2;
codeThatChangesOtherInputValuesOnMyPage3;
codeThatChangesOtherInputValuesOnMyPage4;
codeThatChangesOtherInputValuesOnMyPage5;
codeThatChangesOtherInputValuesOnMyPage6;
codeThatChangesOtherInputValuesOnMyPage7;
codeThatChangesOtherInputValuesOnMyPage8;
var tableColumn = $(ev.target).attr('table-col');
var newFieldValue = $(ev.target).val()
if (!ev.data.comingFromBroadcastReceiverFunction) {
broadcastChange(tableColumn, newFieldValue); // this is pseudo code for a socket-io emit()
}
});
but you can't pass data to change(); only when binding the function.
What do you guys think is the functional programming approach to this?
If you are copying and pasting code over and over, you could avoid that by separating the duplicate code into a new function, and have both the change and the socket functions call it.
For example, it could work like this:
function updateInputValue(inputField) {
codeThatChangesOtherInputValuesOnMyPage1;
codeThatChangesOtherInputValuesOnMyPage2;
codeThatChangesOtherInputValuesOnMyPage3;
codeThatChangesOtherInputValuesOnMyPage4;
codeThatChangesOtherInputValuesOnMyPage5;
codeThatChangesOtherInputValuesOnMyPage6;
codeThatChangesOtherInputValuesOnMyPage7;
codeThatChangesOtherInputValuesOnMyPage8;
}
$(".input-field").change(function(ev) {
updateInputValue($(ev.target));
var tableColumn = $(ev.target).attr('table-col');
var newFieldValue = $(ev.target).val()
broadcastChange(tableColumn, newFieldValue); // this is pseudo code for a socket-io emit()
});
socket.on('runThisWhenReceivingBroadcastFromServer', function(response) {
// response.data has the input element id of element I should update.
// Get the input field i should update
var theInputField = getInputField(response.data)
$(theInputField).val(getNewInputValue(response.data))
updateInputValue($(theInputField));
// I call change because I want all my code in the input's change function to run, except for the last line.
});

My EventListener to a button continues to fire despite ownership being changed, why? (JavaScript)

I have a function, which at the end of its task assigns a button to a new id.
function altChecker() {
var doc = document,
out = [],
appButton = doc.getElementById('appButton'),
//re = /click-me/gi,
output = doc.createElement('p');
output.setAttribute('id', 'output');
EventUtility.addHandler(appButton, 'click', function(e) {
//I have not included all the function details to concentrate on the question
appButton.id = 'appButtonNextChecker';
var appButtonNextChecker = doc.getElementById('appButtonNextChecker');
nextChecker(appButtonNextChecker);
});
}
function nextChecker(newBtnName) {
EventUtility.addHandler(newBtnName, 'click', function(e) {
$('#output').innerHTML = "";
console.log('next Checker, button!')
});
}
So basically there is one button in the DOM assigned to appButton ID initially, and then I change it doing:
appButton.id = 'appButtonNextChecker';
when the altChecker function fires...
Then I assign the button to a new variable, and pass in the variable to the next function...
var appButtonNextChecker = doc.getElementById('appButtonNextChecker');
nextChecker(appButtonNextChecker);
While I can see the buttons' ID change in the DOM, and I see the console.log fire in the nextChecker function,
$('#output').innerHTML = ""; //doesn't fire
AND the altChecker function fires as well (again)?! Haven't I severed the connection to the click function when I reassigned the new ID?
Any help would be appreciated!
Javascript doesn't remember that you initially attached the event through it's id. The event is attached to the element itself, not the ID. It's not like CSS that way.
In fact your variables are still holding the same element as well, so there's no need to create a new variable after changing the ID, either. Since you're using jQuery you can just type $(appButton).unbind(); to remove the event handler. You may also want to look into .on() and .off()
The problem is that you're trying to use the innerHTML property in a jQuery's object.
That property belongs to Element, and it will not work in the way you're using it.
You can use the document.getElementById method, and it will work fine:
document.getElementById('output').innerHTML = '';
Or you can use jQuery's html method:
$('#output').html('');
And you can even use the first element of the jQuery's array, and use innerHTML again:
$('#output')[0].innerHTML = '';
It's up to you, but the first option will be faster, for sure.

jQuery Plugin - Public method - Data only targeting one element

I'm trying to write a plugin that will select multiple elements and then apply some private methods to them (see code below). Then I also want to give the user the ability to trigger the activation of the plugin's methods manually with a .activate() function.
Here is my code :
MARKUP : https://github.com/simonwalsh/jquery.imagepox/blob/master/demo/index.html
JS : https://github.com/simonwalsh/jquery.imagepox/blob/master/dist/jquery.imagepox.js
Basically, when I select multiple items and then try to use the manual activation like so :
$(".pox-wrapper").imagepox({ // NOTE: selects two elements
manualActivation: true
});
var manual = $(".pox-wrapper").data('imagepox');
setTimeout(function(){
manual.activate();
}, 5000);
It will only apply the activate() method to the first element in the query...
This is my first jQuery plugin and I've been able to handle everything so far but I'm not sure about this one or even if it is the right way to effectively call a public method. I also tried using a custom event with an event listener in the plugin but it still only applies the methods on the first element in the page.
Thanks in advance :)
its not your plugin's fault. data does not work like that, it doesnt know how to return data from a collection of elements. Because think about it, each element in the collection contains its own data object!
So when you call data on a collection, it returns the data from the first one. The quick solution would be to change the innards of the setTimeout into a loop over all the elements in the set and call activate on them.
setTimeout(function(){
$(".pox-wrapper").each(function(){
$(this).data('imagepox').activate();
})
}, 5000);
It seems to me that you want to add functions to collections of jquery objects. This is the usecase of a jquery plugin. You can create a lightweight one like this:
$.fn.imagepox.activate = function(){ //do this after you create your plugin!
return this.each(function(){
var $this = $(this);
var data = $this.data('imagepox');
if(data){
data.activate();
}
});
};
now you can call it like this:
$(".pox-wrapper").imagepox.activate()

How can I add a link to dynamically created button?

Once the buttons are created, is there anyway I can add a link or use window.location method like this: `window.location = 'nextpage.html?foo=number'. I currently have this
var typeValue = location.search;
var typeStringValue= typeValue.replace("?type=","");
var containers = typeValue.replace("?type=multi","");
var containersValue = parseInt(containers);
var sampleLetter = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
function createButton(buttonName){
var buttonDivBlock = document.getElementById("sampleSets");
var buttonElement = document.createElement("input");
buttonElement.setAttribute("type","button");
buttonElement.setAttribute("name",buttonName);
buttonElement.setAttribute("value","Sample Set"+" "+buttonName);
buttonElement.setAttribute("id",buttonName);
buttonDivBlock.appendChild(buttonElement);
// document.getElementById(sampleLetter[i]).setAttribute('onclick',window.location='SampleInfo.html'+typeStringValue+bottonName);<!--add the button link -->
}
function setButtons(numberOfContainers){
for(i=0;i<numberOfContainers;i++){
createButton(sampleLetter[i]);
}
}
window.onload = function(){
setButtons(containersValue);
}
But document.getElementById("'"+sampleLetter[i]+"'").setAttribute('onclick',window.location='SampleInfo.html'+typeStringValue+bottonName);<!--add the button link -->
returns a null value.
Well, maybe I can help you along with an example:
function getFive() { return 5;}
callOtherFunction("stringArgument", getFive());
The second argument to callOtherFunction is going to be 5, not the getFive function. In many cases, like adding event listeners and AJAX code, you actually want to pass the function itself as an argument, so it can be called later. But if you don't want to bother declaring that function seperately, it looks like this:
callOtherFunction("stringArgument", function() { return 5; });
To make code look cleaner, you can press Enter after the { and make a multi-line function.
Now, all that in mind, take another look at the line you've commented out. Do you see what's missing? (PS. Apologies for the "egging-on" format - I find people get much better at figuring things out if I help them find the solution, rather than just showing it to them)
The sampleLetter variable is not defined where you are trying to use it (judging by commented code). Use the value you had just set to the id attribute a few lines earlier.
document.getElementById(buttonName).setAttribute( /* ... */ );
Or if you are trying to set it in the loop instead of in the createButton function, do not add the single quotes
document.getElementById(sampleLetter[i]).setAttribute( /* ... */ );

how to pass Id to javascript dynamically

function jsarea3() { document.getElementById("Txtarea3").title = document.getElementById("Txtarea3").value; }
function jsarea4() { document.getElementById("Txtarea4").title = document.getElementById("Txtarea4").value; }
function jsarea5() { document.getElementById("Txtarea5").title = document.getElementById("Txtarea5").value; }
The code above is to show data in a textbox area on mouse hover.
as you can see the code that run is same for all the 3 function the difference is only the ID
How can I pass ID dynamically
Like I can use the inner code as function as well for all the 3 and how to use it
and what about code like this the code given below
$('#button1').focus(function () {
$('#button1', window.parent.document).css("background-color", "#fcc63b");
}
});
if you are using jquery you can select your textareas like this
$("textarea").focus(function(){
this.title = $(this).val();
});
you can specify the selector to be more specific to the items that you want to manipulate
the function will be running when your textarea gain focus
take a look at jquery it's simplify your code
Since you use the same elements title and value you can store a reference instead of searching for it twice..
function jsarea(anId) {
var elem = document.getElementById(anId);
elem.title = elem.value;
}
and you can call it with jsarea('Txtarea3');
For the second code, it is jQuery code and it seems to change the background color of a button with the same id as the one that gets the focus in the parent window (when you use iframes)
You can use a single function which takes a parameter representing the id of the the element you wish to reference:
function jsarea(elementId) {
document.getElementById(elementId).title = document.getElementById(elementId).value;
}
You can call this like jsarea("Txtarea3"); if you want to affect the element with id "Txtarea3".
Use a parameter.
In addition, you should take a look at jQuery - it can really simplify DOM-manipulating code.
function jsarea(number) { document.getElementById("Txtarea" + number).title = document.getElementById("Txtarea" + number).value; }

Categories

Resources