I have this method that is recursively called.
This method creates a li that ll be used on Iscroll plugin.
My problem is:
The input button does not works. On his CSS I set cursor:pointer to check if the input is recognized, and it is. But I can click it several times that does nothing.
createList: function(p_id)
{
var lv_linhaDoc = '<li id="lis_' + p_id + '" class="listItem">' +
'<div class = "alinhar1" onClick="lis.Click(' + p_id + ', false)">' +
'<div class="ui-grid-a" style="font-size: large">' +
'<div class="ui-block-a"><p class="header" style="font-size: medium"><strong>' + 4 + '</strong></p></div>' +
'<div class="ui-block-a"><p class="line label"><strong>Data Criação</strong></p></div>' +
'<div class="ui-block-b"><p class="line value" style="text-align: right">' + '13/2/14' + '</p></div>' +
'<div class="ui-block-a"><p class="line label total"><strong> Valor</strong></p></div>' +
'<div class="ui-block-b"><p class="line total" style="text-align: right">' + 13 + ' ' + 15 + '</p></div>' +
'</div></div>' +
' <input type="button" class=" button_add" onClick="lis.Detail(' + p_id + ')" />' +
'</li>';
return lv_linhaDoc;
},
The problem is not in the Detail() function bacause I can't enter in that function because the click is not recognized
UPDATE
I found that the input button stopped working after I add these to the IScroll initialization
click: true,
tap: true,
I really need those arguments in the IScroll to do other fucntions.
IScroll initialization:
initScroll: function(){
var wrapper = document.getElementById('id5');
myScroll = new IScroll(wrapper, {
// click: true,
// tap: true,
scrollX : false,
scrollY : true,
scrollbars : false,
interactiveScrollbars : true,
mouseWheel : false,
hScrollbar : false,
vScrollbar : true,
useTransition : false,
snap : 'li',
indicators : {
el : '#scroller',
fade : false,
ignoreBoundaries : false,
interactive : false,
listenX : false,
listenY : true,
resize : false,
shrink : false,
speedRatioX : 0,
speedRatioY : 0,
checkDOMChanges: true,
},
});
Instead of trying to add the click handler inline, you can save the p_id as a data-attribute on the input and then setup a click handler using event delegation. With delegation you can setup a handler on elements that will be created dynamically later.
When creating the listitem, put the p_id in a data-attribute of the input e.g. data-pid:
<input type="button" class="button_add" data-pid="' + p_id + '" value="+" />
Then add a click handler that delegates to the .button_add class. In that handler you can retrieve the p_id from the data-attribute:
$(document).on("click", ".button_add", function(e){
var p_id = $(this).data("pid");
alert(p_id);
//call detail function and pass in the p_id
});
DEMO
You need to do something like below :
createList: function(p_id)
{
var lis = new lisClass();
var lv_linhaDoc = '<li id="lis_' + p_id + '" class="listItem">' +
'<div class = "alinhar1" onClick="lis.Click(' + p_id + ', false)">' +
'<div class="ui-grid-a" style="font-size: large">' +
'<div class="ui-block-a"><p class="header" style="font-size: medium"><strong>' + 4 + '</strong></p></div>' +
'<div class="ui-block-a"><p class="line label"><strong>Data Criação</strong></p></div>' +
'<div class="ui-block-b"><p class="line value" style="text-align: right">' + '13/2/14' + '</p></div>' +
'<div class="ui-block-a"><p class="line label total"><strong> Valor</strong></p></div>' +
'<div class="ui-block-b"><p class="line total" style="text-align: right">' + 13 + ' ' + 15 + '</p></div>' +
'</div></div>' +
' <input type="button" class=" button_add" onClick="lis.Detail(' + p_id + ')" />' +
'</li>';
return lv_linhaDoc;
},
You see i have aded var lis = new lisClass();
Just found the solution:
There's a bug on IScroll that if the parameter click is enable then all the form elements, such as the submit button do not work with iScroll.
So, I did this:
myScroll = new IScroll(wrapper, {
click: false,
scrollX : false,
scrollY : true,
scrollbars : false,
interactiveScrollbars : true,
mouseWheel : false,
hScrollbar : false,
vScrollbar : true,
useTransition : false,
snap : 'li',
preventDefaultException: {tagName:/.*/},
indicators : {
el : '#scroller',
fade : false,
ignoreBoundaries : false,
interactive : false,
listenX : false,
listenY : true,
resize : false,
shrink : false,
speedRatioX : 0,
speedRatioY : 0,
checkDOMChanges: true,
},
});
Notice that the parameter clickis now as false and i add the preventDefaultException: {tagName:/.*/},
I found this here
Related
I have a log in button that when a user clicks on it a terms and condition dialog pops up and overlaps the contents on a page as follows
TermsSuccess: function (result, context) {
var topTerms = findSetByInArray(result.Data, 'ParentId', 0);
var termsHTML = '<div id="terms"><ul class="termsList">';
for (var i = 0; i < topTerms.length; i++) {
var cls = (topTerms[i].isNew) ? 'newTerm' : 'Term';
termsHTML += '<li id=' + topTerms[i].ID + ' class=' + cls + '>'
termsHTML += topTerms[i].PageIndex + '. ' + topTerms[i].Detail;
termsHTML += getChildrenTerms(result.Data, topTerms[i].ID, topTerms[i].PageIndex + '. ');
termsHTML += '</li>';
}
termsHTML += '</ul></div>';
$(termsHTML).dialog({
modal: true,
resizable: false,
width: 400,
height: 600,
closeOnEscape: false,
open: function (event, ui) {
$(this).parent().children().children('.ui-dialog-titlebar-close').hide();
},
title: "Terms & Conditions",
buttons: [{
text: "Decline",
"class": 'btnDialog',
click: function () {
$(this).dialog("close");
}
},
{
text: "Accept",
"class": 'btnDialog',
click: function () {
betEvents.btnAccept_onClick();
$(this).dialog("close");
}
}]
});
}
I want this dialog to be appended to the following div on the page instead of it poping up over all the contents
<div id="mainarea"></div>
i tried to do something as the following but it doesnt work
function onClick(){
if $("#btnLogin").click(function(){
$('termsHTML').append('#mainarea');
});
}
your guidance will be appreciated.
Change this line:
$('termsHTML').append('#mainarea');
to
$(#mainarea).append(termsHTML);
and try again.
Explanation: $('termsHTML').append('#mainarea'); // here your selector is wrong
I build a function to display a value in a HTML element for a
<input type="range">
object.
My function works fine:
var rangeValues = { "50": "Fifty" , "100": "Hundred" , "...": "..." };
$(function Skilllevel() {
$('#rangeText').text(rangeValues[$('#rangeInput').val()]);
$('#rangeInput').on('input change', function ()
{
$('#rangeText').text(rangeValues[$(this).val()]);
});
});
See example in jsfiddle
My problem now is the following:
I putted the function Skilllevel() into a $.each(result, function and into it, it doesn't work, because every entry from my second JSON file var urlBewerbungID = "json.php"; generated one separate list element in $("#ergebnisSkill").append(
The second JSON looks very simple, like this:
[
"item1",
"item2",
"item3"
]
My complete function:
//Skills selektieren
var rangeValues = {
"0": "Keine",
"33": "Anfänger",
"66": "Fortgeschritten",
"99": "Profi"
};
//Abfrage, welche Stelle gewählt wurde
$('#bewerbungID').on('change', function() {
var bewerbungID = ($('#bewerbungID').val());
console.log("BewerbungsID gewählt: " + bewerbungID);
//Zuerst das #HTML Element leeren
$("#ergebnisSkill").empty();
$(document).ready(function() {
var urlBewerbungID = "json.php";
$.getJSON(urlBewerbungID, function(result) {
console.log(result);
$.each(result, function(i, field) {
var skill = field;
//Skill liste erstellen
$(function Skilllevel() {
$('#rangeText').text(rangeValues[$('#rangeInput').val()]);
$('#rangeInput').on('input change', function() {
$('#rangeText').text(rangeValues[$(this).val()]);
});
});
//Jetzt HTML Element neu befüllen
$("#ergebnisSkill").append(
'<li>' +
'<div class="item-content">' +
'<div class="item-media"><i class="icon f7-icons">star</i></div>' +
'<div class="item-inner">' +
'<div class="item-title label">' + skill + '<br> <span id="rangeText"></span></div>' +
'<div class="item-input">' +
'<div class="range-slider">' +
'<input type="range" id="rangeInput" min="0" max="99" value="0" step="33">' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</li>'
);
});
});
});
});
Your code is inside out.
You need document.ready to wrap the event handlers.
Use class instead of IDs, IDs need to be unique
use delegation - currently you have a function per result which does not work.
You need the skills functionality assigned to each result but delegated - see how a click on the ergebnisSkill will be captured by the rangeInput:
//Skills selektieren
var rangeValues = {
"0": "Keine",
"33": "Anfänger",
"66": "Fortgeschritten",
"99": "Profi"
};
$(document).ready(function() {
//Skill liste erstellen
$("#ergebnisSkill").on('input change', ".rangeInput", function() { // delegation
$(this).closest("item-inner") // a parent div
.find('.rangeText') // the input field
.text(rangeValues[$(this).val()]);
});
//Abfrage, welche Stelle gewählt wurde
$('#bewerbungID').on('change', function() {
var bewerbungID = ($('#bewerbungID').val());
console.log("BewerbungsID gewählt: " + bewerbungID);
//Zuerst das #HTML Element leeren
$("#ergebnisSkill").empty();
var urlBewerbungID = "json.php";
$.getJSON(urlBewerbungID, function(result) {
console.log(result);
$.each(result, function(i, field) {
var skill = field;
//Jetzt HTML Element neu befüllen
$("#ergebnisSkill").append(
'<li>' +
'<div class="item-content">' +
' <div class="item-media"><i class="icon f7-icons">star</i></div>' +
' <div class="item-inner">' +
' <div class="item-title label">' + skill + '<br> <span class="rangeText"></span></div>' +
' <div class="item-input">' +
' <div class="range-slider">' +
' <input type="range" class="rangeInput" min="0" max="99" value="0" step="33">' +
' </div>' +
' </div>' +
' </div>' +
'</div>' +
'</li>'
);
});
});
});
});
I have a chat window with a jScrollPane. The problem is that when I submit a message it doesn't scroll down to the last word/line I wrote, it's always a line behind.
$('body').delegate('#private-form', 'submit', function() {
var sendMessage = $(this).find('input.private-message').val();
if (!empty(sendMessage)) {
socket.emit('send private message', {
'message': sendMessage,
'username': $(this).find('input.send-to').val()
});
$(this).find('input.private-message').val('');
var data = '' +
'<div class="person">' +
'<img src="img/avatar.png" alt="">' +
'<div class="details">' +
'<div class="chat">' +
'<p>' + sendMessage + '</p>' +
'</div>' +
'<div class="chat-view">' +
'<p>10 min ago</p>' +
'</div>' +
'</div>' +
'</div>';
var settings = {
showArrows: false,
autoReinitialise: true,
};
var pane = $('.chat-single');
pane.jScrollPane(settings);
var contentPane = pane.data('jsp').getContentPane();
contentPane.append(
data
);
pane.data('jsp').scrollToBottom();
}
return false;
});
Markup:
<div class="chatters">
<div class="chat-single">
</div>
</div>
Styles:
.chatters {
padding: 10px 0;
height: 75%;
width: auto;
max-width: 390px;
}
.chat-single{
height:100%
}
After appending the data, call reinitialise on pane.data('jsp') before scrolling to the bottom.
contentPane.append(
data
);
pane.data('jsp').reinitialise();
pane.data('jsp').scrollToBottom();
Also, if you're using autoReinitialise be sure to provide a reasonable autoReinitialiseDelay since by default it does this re-initialisation twice per sencond (every 500ms).
Code to create the grid:
var grid = $("#grid").kendoGrid({
dataSource: [],
columnMenu: true,
scrollable: true,
sortable: false,
filterable: true,
groupable: true,
columns: [{
field: "Id",
title: "Id",
filterable: false
}, {
field: "title",
title: "Title"
}]
}).data("kendoGrid");
I have also customized Array's prototype in this way:
Function.prototype.method = function (name, func) {
"use strict";
if (!this.prototype[name]) {
this.prototype[name] = func;
return this;
}
};
Array.method('contains', function (object) {
return $.inArray(object, this) !== -1;
});
Result: whenever I try to open the column menu for any column, I get:
Uncaught TypeError: Cannot call method 'replace' of undefined
See a demonstration of the bug at http://jsfiddle.net/lhoeppner/sNdVR/
This is a flaw in kendoColumnMenu (affects versions up to 2013.2.1002) which leads to a bug under the following conditions:
Array.prototype is changed to have additional methods, e.g. "contains"
Grid options contain columnMenu: true
The private var "template" in kendoColumnMenu needs to be changed: in the for loop, add a check for hasOwnProperty in the following form:
'#if (columns.hasOwnProperty(col)) {#' +
The complete template would then be:
var template = '<ul>' +
'#if(sortable){#' +
'<li class="k-item k-sort-asc"><span class="k-link"><span class="k-sprite k-i-sort-asc"></span>${messages.sortAscending}</span></li>' +
'<li class="k-item k-sort-desc"><span class="k-link"><span class="k-sprite k-i-sort-desc"></span>${messages.sortDescending}</span></li>' +
'#if(showColumns || filterable){#' +
'<li class="k-separator"></li>' +
'#}#' +
'#}#' +
'#if(showColumns){#' +
'<li class="k-item k-columns-item"><span class="k-link"><span class="k-sprite k-i-columns"></span>${messages.columns}</span><ul>' +
'#for (var col in columns) {#' +
'#if (columns.hasOwnProperty(col)) {#' +
'<li><input type="checkbox" data-#=ns#field="#=columns[col].field.replace(/\"/g,"&\\#34;")#" data-#=ns#index="#=columns[col].index#"/>#=columns[col].title#</li>' +
'#}#' +
'#}#' +
'</ul></li>' +
'#if(filterable){#' +
'<li class="k-separator"></li>' +
'#}#' +
'#}#' +
'#if(filterable){#' +
'<li class="k-item k-filter-item"><span class="k-link"><span class="k-sprite k-filter"></span>${messages.filter}</span><ul>' +
'<li><div class="k-filterable"></div></li>' +
'</ul></li>' +
'#}#' +
'</ul>';
The only way to fix this at the moment is to edit kendo UI's source code for kendoColumnMenu.
I have fineupload working with one button, but I would like to have several upload buttons on 1 page. But cannot get it to work...
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Fine Uploader - Boostrapped Minimal Demo</title>
<link href="/fineuploader/fineuploader-3.3.0.css" rel="stylesheet">
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.1.1/css/bootstrap.min.css" rel="stylesheet">
<style>
/* Fine Uploader
-------------------------------------------------- */
.qq-upload-list {
text-align: left;
}
/* For the bootstrapped demos */
li.alert-success {
background-color: #DFF0D8 ;
}
li.alert-error {
background-color: #F2DEDE ;
}
.alert-error .qq-upload-failed-text {
display: inline;
}
</style>
</head>
<body>
<div id="bootstrapped-fine-uploader-1"></div>
<script src="/fineuploader/fineuploader-3.3.0.js"></script>
<script>
function createUploader() {
var uploader = new qq.FineUploader({
element: document.getElementById('bootstrapped-fine-uploader-1'),
request: {
endpoint: 'example.php?naam=test.jpg'
},
text: {
uploadButton: '<div><i class="icon-upload icon-white"></i> Test me now and upload a file</div>'
},
template: '<div class="qq-uploader span12">' +
'<pre class="qq-upload-drop-area span12"><span>{dragZoneText}</span></pre>' +
'<div class="qq-upload-button btn btn-success" style="width: auto;">{uploadButtonText}</div>' +
'<span class="qq-drop-processing"><span>{dropProcessingText}</span><span class="qq-drop-processing-spinner"></span></span>' +
'<ul class="qq-upload-list" style="margin-top: 10px; text-align: center;"></ul>' +
'</div>',
classes: {
success: 'alert alert-success',
fail: 'alert alert-error'
}
});
}
window.onload = createUploader;
</script>
<div id="bootstrapped-fine-uploader-2"></div>
<script src="/fineuploader/fineuploader-3.3.0.js"></script>
<script>
function createUploader() {
var uploader = new qq.FineUploader({
element: document.getElementById('bootstrapped-fine-uploader-2'),
request: {
endpoint: 'example.php?naam=test2.jpg'
},
text: {
uploadButton: '<div><i class="icon-upload icon-white"></i> Upload jpg</div>'
},
template: '<div class="qq-uploader span12">' +
'<pre class="qq-upload-drop-area span12"><span>{dragZoneText}</span></pre>' +
'<div class="qq-upload-button btn btn-success" style="width: auto;">{uploadButtonText}</div>' +
'<span class="qq-drop-processing"><span>{dropProcessingText}</span><span class="qq-drop-processing-spinner"></span></span>' +
'<ul class="qq-upload-list" style="margin-top: 10px; text-align: center;"></ul>' +
'</div>',
classes: {
success: 'alert alert-success',
fail: 'alert alert-error'
}
});
}
window.onload = createUploader;
</script>
</body>
</html>
Only the second button is displayed, the first one completely disappears... Is there someone who can help me with this ?
You're assigning the window.onload event the first function, then replacing it with the second one. You should assign the event only once. Also, you don't need two separate script tags.
<body>
<div id="bootstrapped-fine-uploader-1"></div>
<div id="bootstrapped-fine-uploader-2"></div>
<script src="fineuploader-3.3.0.js"></script>
<script>
function createUploaders() {
var uploader1 = new qq.FineUploader({
element: document.getElementById('bootstrapped-fine-uploader-1'),
request: {
endpoint: 'example.php?naam=test.jpg'
},
text: {
uploadButton: '<div><i class="icon-upload icon-white"></i> Test me now and upload a file</div>'
},
template: '<div class="qq-uploader span12">' +
'<pre class="qq-upload-drop-area span12"><span>{dragZoneText}</span></pre>' +
'<div class="qq-upload-button btn btn-success" style="width: auto;">{uploadButtonText}</div>' +
'<span class="qq-drop-processing"><span>{dropProcessingText}</span><span class="qq-drop-processing-spinner"></span></span>' +
'<ul class="qq-upload-list" style="margin-top: 10px; text-align: center;"></ul>' +
'</div>',
classes: {
success: 'alert alert-success',
fail: 'alert alert-error'
}
});
var uploader2 = new qq.FineUploader({
element: document.getElementById('bootstrapped-fine-uploader-2'),
request: {
endpoint: 'example.php?naam=test2.jpg'
},
text: {
uploadButton: '<div><i class="icon-upload icon-white"></i> Upload jpg</div>'
},
template: '<div class="qq-uploader span12">' +
'<pre class="qq-upload-drop-area span12"><span>{dragZoneText}</span></pre>' +
'<div class="qq-upload-button btn btn-success" style="width: auto;">{uploadButtonText}</div>' +
'<span class="qq-drop-processing"><span>{dropProcessingText}</span><span class="qq-drop-processing-spinner"></span></span>' +
'<ul class="qq-upload-list" style="margin-top: 10px; text-align: center;"></ul>' +
'</div>',
classes: {
success: 'alert alert-success',
fail: 'alert alert-error'
}
});
}
window.onload = createUploaders();
</script>
</body>
Here's how I've done it.
It is more code initially but makes sense. You can place as many uploaders on one page as you want.
if (self.settings.businessAddresses !== null) {
$.each(self.settings.businessAddresses, function (index, businessAddress) {
initFileUploader(self.settings.privateAddresses.length + index, businessAddress, "business", self.settings.allowedExtensions);
});
}
Here's implementation of 'generic' file uploader initializer. Mind you it is Fine Uploader 2.1.2 i am using. It should be easier in new version i suppose. I have extensions.js to go with it to support separate parameters for each individual file too and some other improvements which probably have been addressed in new version of file uploader.
// initiate uploader
function initFileUploader(index, addressInstance, addressType, allowedFileExtensions) {
var filesCount = 0;
var uploadButtonSelector = '#triggerUpload-' + addressInstance.Id;
var fileSelectButton = ".qq-upload-button-" + addressInstance.Id;
var uploadedFilesErrorSelector = '#uploadedFilesError-' + addressInstance.Id;
var nextButtonSelector = "#Next";
var previousButtonSelector = "#Previous";
var documentTypeSelector = "#DocumentTypeCode-" + addressInstance.Id;
var prospectCacheKeySelector = "#ProspectCacheKey";
// Set up the upload API
var fileUploader = new qq.FileUploader({
element: $('#filesToUpload-' + addressInstance.Id)[0],
action: '/FileUploader',
autoUpload: false,
uploadButtonText: 'Select a file',
allowedExtensions: allowedFileExtensions,
sizeLimit: 1048576, // 1 MB = 1024 * 1024 bytes,
template: '<div class="qq-uploader">' + // Allow the boostrap styles
'<div class="qq-upload-button-' + addressInstance.Id + ' btn btn-success" style="width: 100px">{uploadButtonText}</div>' +
'<ul class="qq-upload-list-' + addressInstance.Id + '" style="margin-top: 10px; text-align: center;"></ul>' +
'<pre class="qq-upload-drop-area-' + addressInstance.Id + '"><span>{dragText}</span></pre>' +
'</div>',
failUploadText: '',
fileTemplate: '<li>' +
'<span class="qq-document-type-' + addressInstance.Id + '"></span>' +
'<span class="qq-upload-file-' + addressInstance.Id + '">10870</span>' +
'<a class="qq-upload-cancel-' + addressInstance.Id + '" href="#"> Remove</a>' +
'<div class="qq-progress-bar-' + addressInstance.Id + '"></div>' +
'<span class="qq-upload-spinner-' + addressInstance.Id + '" style="display: none;"></span>' +
'<span class="qq-upload-finished-' + addressInstance.Id + '"></span>' +
'<span class="qq-upload-size-' + addressInstance.Id + '" style="display: none;"></span>' +
'<span class="qq-upload-failed-text-' + addressInstance.Id + '"></span>' +
'</li>',
classes: {
button: 'qq-upload-button-' + addressInstance.Id + '',
drop: 'qq-upload-drop-area-' + addressInstance.Id + '',
dropActive: 'qq-upload-drop-area-active-' + addressInstance.Id + '',
dropDisabled: 'qq-upload-drop-area-disabled-' + addressInstance.Id + '',
list: 'qq-upload-list-' + addressInstance.Id + '',
progressBar: 'qq-progress-bar-' + addressInstance.Id + '',
file: 'qq-upload-file-' + addressInstance.Id + '',
documentType: 'qq-document-type-' + addressInstance.Id + '',
applicationId: 'qq-application-id-' + addressInstance.Id + '',
addressId: 'qq-address-id-' + addressInstance.Id + '',
addressType: 'qq-address-type-' + addressInstance.Id + '',
spinner: 'qq-upload-spinner-' + addressInstance.Id + '',
finished: 'qq-upload-finished-' + addressInstance.Id + '',
size: 'qq-upload-size-' + addressInstance.Id + '',
cancel: 'qq-upload-cancel-' + addressInstance.Id + '',
failText: 'qq-upload-failed-text-' + addressInstance.Id + '',
success: 'alert-success',
fail: 'alert-error',
successIcon: null,
failIcon: null
},
onError: function (id, fileName, errorReason) {
alert(errorReason);
},
onComplete: function (id, fileName, response) {
filesCount--;
if (response.success) {
$('<input>').attr({
type: 'hidden',
name: 'UploadedFileIds',
value: response.cacheKey
}).appendTo('form');
}
// Check that we have finished downloading all files
if (fileUploader.getInProgress() == 0) {
// Re-enable the Next button
$(nextButtonSelector).removeAttr('disabled');
$(previousButtonSelector).removeAttr('disabled');
$(uploadButtonSelector).css('visibility', 'hidden');
}
},
onSubmit: function (id, fileName) {
filesCount++;
fileUploader._options.params[id] =
{
documentType: $("select" + documentTypeSelector)[0].value,
documentTypeText: $("select" + documentTypeSelector)[0].options[$("select" + documentTypeSelector)[0].selectedIndex].text,
addressId: addressInstance.Id,
addressType: addressType,
applicationId: addressInstance.ApplicationId,
prospectCacheKey: $(prospectCacheKeySelector).val()
};
// $(documentTypeSelector).prop('selectedIndex', 0);
// $(fileSelectButton).attr('disabled', 'disabled');
// Show the upload button
if ($(uploadButtonSelector).css('visibility') === 'hidden') {
$(uploadButtonSelector).css('visibility', 'visible');
}
// Hide the error for mandatory files upload
$(uploadedFilesErrorSelector).css('display', 'none');
},
onCancel: function (id, fileName) {
filesCount--;
if (filesCount === 0) {
$(uploadButtonSelector).css('visibility', 'hidden');
}
}
});
You have two globally-scoped functions with the same name. The second createUploader overwrites the first createUploader.