multiple instances of valums file uploader - javascript

I'm trying to get multiple instances of valum file uploader working on my site. It works great with one instance but anytime I loop over initialization code, wanting multiple buttons I don't see any buttons. Here's the code:
<cfoutput query="getTopics">
<script>
function createUploader(){
var uploader = new qq.FileUploader({
element: document.getElementById('file-uploader#refTopicID#'),
action: 'components/ProjectBean.cfc',
params: {method: 'Upload',
topicID: #refTopicID#,
count: #Evaluate("session.#refTopicAbv#Count")#,
topicName: '#refTopicAbv#'
},
encoding: 'multipart'
});
}
// in your app create uploader as soon as the DOM is ready
// don't wait for the window to load
window.onload = createUploader;
</script>
<div class="row" id="file-uploader#refTopicID#">
</div>
Any idea how to get multiple instance? Thanks in advance!

You're creating a javascript function inside of a loop. In other words you're defining it multiple times.
Instead you should move the createUploader function outside of your loop. And within the loop, simply call it multiple times for each of your topics.
Something like this:
<script>
function createUploader(elementID, topicID, topicCount, topicName){
var uploader = new qq.FileUploader({
element: document.getElementById(elementID),
action: 'components/ProjectBean.cfc',
params: {method: 'Upload',
topicID: topicID,
count: topicCount,
topicName: topicName
},
encoding: 'multipart'
});
}
</script>
<cfoutput query="getTopics">
<script>
createUploader('file-uploader#getTopics.refTopicID#', #getTopics.refTopicID#, #session[getTopics.refTopicAbv & "Count"]#, '#getTopics.refTopicAbv#');
</script>
<div class="row" id="file-uploader#getTopics.refTopicID#"> </div>
</cfoutput>
NB: I'm assuming the values all come from your query getTopics, so I've prefixed them with the query name to scope them properly. This isn't usually essential, but it's good practice for performance reasons (among other things).

Related

Asp.net Project - Javascript button is clickable but not carrying out the function

I've been trying to integrate an api into a project that I have been working on with some friends but I'm having difficulty with getting the "ok" button to actually execute the function. It's supposed to allow you to upload a photo, click ok, and then it returns data about the plant. The "choose files button works, but the ok button doesn't.
Since the API sample was already created I tested it in a separate solution and was able to get it to work which leads me to believe that I've made a mistake in the code somewhere else or maybe there's something blocking the program from talking to API's web address. But for some reason it doesn't work within the project that I'm trying to integrate it into. (ASP.NET razor page).
I've also tried making a new button and moving the javascript tag into the header and other spots but that didn't work either, and I've run out of ideas to try. I have omitted the api key itself below for the sake of privacy. I'd really appreciate any help on the subject!
#{
ViewData["Title"] = "Identify a Plant";
}
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<form>
<input type="file" multiple />
<!--<button type="button">OK</button> -->
<button type="button">OK</button>
</form>
<script type="text/javascript">
document.querySelector('button').onclick = function sendIdentification() {
const files = [...document.querySelector('input[type=file]').files];
const promises = files.map((file) => {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (event) => {
const res = event.target.result;
console.log(res);
resolve(res);
}
reader.readAsDataURL(file)
})
})
Promise.all(promises).then((base64files) => {
console.log(base64files)
const data = {
api_key: "Die8ewFGvpw5JrRTuOEjgGR10uL--",
images: base64files,
modifiers: ["crops_fast", "similar_images"],
plant_language: "en",
plant_details: ["common_names",
"url",
"name_authority",
"wiki_description",
"taxonomy",
"synonyms"]
};
fetch('https://api.plant.id/v2/identify', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});
})
};
</script>
</body>
</html>
I think you are better off to give the button a "ID" and you don't.
and I never really did like this idea of "selecting" some button and then hoping we can attached a click event to that button. So, I always preferred that you have a button. You place a button. You specify a click event for that button. You have to really struggle to figure out which button that selector going to pick up - which one does it like?
And then when you click on that button, the code or function runs. It just a lot easier to follow.
So, your button thus is this:
<form id="form1" runat="server">
<div>
<br />
<input id="myfiles" type="file" multiple="multiple" />
<!--<button type="button">OK</button> -->
<button id="MyButton" type="button" onclick="sendIdentification()" >OK</button>
</div>
</form>
<script type="text/javascript">
function sendIdentification() {
alert('start');
const files = [...document.querySelector('input[type=file]').files];
etc.
The problem is that selector for the click event is subject to the order of the controls and things on the page - might not be picked up correct.
So, just drop in a button. State what that button supposed to do on some click event, and this should help here.
With the querySelector method you add the onClick event on a first button within the document. Since the _Layout.cshtml is rendered first, my first assumption is that you have a button in that view? What about giving an id to the button and adding the onClick event like this:
document.getElementById("myButton").onclick = function sendIdentification() {
//the code
};

Trying to build HTML elements by code, functions included

This is my first post, hoping someone can help me:
I wish to build a web project, where all the HTML elements are stored in database and taken from it to build the web page.
i found a problem with the buttons, i cannot find a way to store the function for a button, i´m using Jquery to build the elements, for now the test element definitions are simulated in some arrays i left at the start of my Js file, the only way i can make the buttons to work is if the functions are hardcoded in the Js file, is there a way for me to bring the functions from database too? and having them in an array?
this is my project sample:
HTML
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<!--script src="functions.js"></script-->
<script src="system.js"></script>
<!--script src="elements.js"></script-->
</head>
<body>
<body onload="addElements()">
<div id="div1"></div>
</body>
</html>
JS File
/**
VARIABLE DEFINITIONS
THESE ARE SUPPOSED TO COME FROM A DATABASE
STILL UNKNOWN HOW TO BRING THE FUNCTIONS, AS STRING THEY ARE NOT ALLOWED. FOR NOW THERE ARE TEST FUNCTIONS.
**/
let buttonIds = ['btn1', 'btn2'];
let buttonText = ['Show Text', 'Show HTML'];
let buttonFunc = [alert1, alert2];
//let buttonFunc = ['alert("Hi");', 'alert("Hello");'];
let paragraphs = ['This is some <b>bold</b> text in a paragraph.', 'another <b>bold</b> test'];
//HELPER FUNCTIONS
// **** THESE ARE SUPPOSED TO COME FROM DATABASE, UNKNOWN HOW TO DO IT. ****
function alert1() {
alert("Hi");
}
function alert2(){
alert("Hello");
}
function addElements(){
for(var p=0; p<paragraphs.length; p++){ addParagraphs('#div1', paragraphs[p]); }
for(var i=0; i<buttonIds.length; i++) { createButton( '#div1', buttonIds[i] , buttonText[i]); }
}
// ANY ELEMENTS FUNCTION IS DEFINED HERE ONCE THE PAGE IS LOADED.
$(document).ready(function(){
for(var x=0;x<buttonIds.length; x++){ activateButton(buttonIds[x], buttonFunc[x]); }
});
//HELPER FUNCTIONS USED TO BUILD THE HTML ELEMENTS ON THE MAIN PAGE.
function addParagraphs(location, text){
$(location).append('<p id="test">'+text+'</p>');
}
function createButton(location, id, text){
var definition;
definition = "<button id="+id+">"+text+"</button>";
$(location).append(definition);
}
function activateButton(buttonId, functionName){
var composedId = "#"+buttonId;
$(composedId).click(functionName);
}
You can generate Javascript file serverside with all the funcions you need.
Supposing Node.js you can do something like this:
expressApp.get("some.js", (req, res) => {
getDataFromDatabase() // depends on your database
.then(data => {
let body = 'function your_fn () { alert("'+ JSON.stringify(data) +'")}';
res.send(body);
})
});
One approach is use an object to store the functions in javascript and use property names stored in db to associate which function to use for which element.
Without knowing more about your use case it is hard to really help design a proper system to use
Following is a very basic example
// functions stored in js file
const funcs = {
f1: function(e){ console.log('func one called , id = ', this.id)},
f2: function(e){ console.log('func 2 called , id = ', this.id)}
}
// data from database
const elems = [
{id: 1, className: 'one', func:'f1', text:'Item 1'},
{id: 1, className: 'two', func:'f2', text:'Item 2'}
]
elems.forEach(e => {
const $el= $('<div>', {id: e.id, class: e.className, text:e.text, click: funcs[e.func]})
$('body').append($el);
});
div {margin:1em;}
.one {color:red;}
.two {color:green;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<strong>Click on items</strong><br><br>

javascript loading sequence

I have a MainView "About.cshtml" it has a script tag in it and a partial view.
<script>
$(function () {}
</script>
<div>
#Html.Partial("~/Views/Maps/_MapDetailsList.cshtml", Model.saVM)
</div>
Inside "_MapDetailList.cshtml" partial view i am referencing another script ge.js
#Scripts.Render("~/Scripts/ge.js")
<table id="MapDetails">
.....
<tr><th>
<script>setGrowthArray(1, 1);</script>
</th></tr>
</table>
ge.js
var dictionaryGrowth = new Array();
function setGrowthArray(colIndex, mapDetailId) {
//making a sparse array
dictionaryGrowth[colIndex] = mapDetailId;
}
Now i want to send this dictionaryGrowth array to server side after the page/table is loaded
so i did the following in the About.cshtml script but didnot work..
<script>
$(function () {
$("#MapDetails").load(function () { alert("everything seems fine");});
}
</script>
Also please tell me what will be the script and DOM loading sequence in my case.
UPDATE
Probably the Current sequence is
Script on About.cshtml is executed
ge.js is executed
document.ready inside partial view is fired
javascript function (setGrowthArray) from inside DOM is called
Now i want to call my controller??
If i write window.onload = ... inside ge.js it is never fired
You can substitute using $.post() for .load(), pass result of setGrowthArray(1, 1) as data posted to server
<script>
$.post("/path/to/server", {growth:setGrowthArray(1, 1)}, function(data) {
console.log(data); // response from server
$("#MapDetails").html(data);
})
</script>

Definition of Function SubmitSurvey have not been found but I defined it

It is literally fifth day I try to solve this.
I try to invoke a method by a button in Razor View, no redirections to other views, just invoke a simple method when button is clicked.
The script looks like:
<script>
function SubmitClick () {
var pid = $(this).data('personid');
var sid = $(this).data('surveyid');
var url = '#Url.Action("SubmitSurvey", "Person")';
$.post(url, { personid: pid, surveyid: sid }, function (data) {
alert('updated');
});
};
</script>
The button looks like:
<button class='mybutton' type='button' data-personid="#Model.Item1.Id" data-surveyid="#survey.Id" onclick="javascript:SubmitClick()">Click Me</button>
The PersonController method looks like:
public void SubmitSurvey(int personId, int surveyId) {
System.Diagnostics.Debug.WriteLine("UPDATING DATABASE");
}
The full view (this is PartialView):
<script>
function SubmitClick () {
var pid = $(this).data('personid');
var sid = $(this).data('surveyid');
var url = '#Url.Action("SubmitSurvey", "Person")';
$.post(url, { personid: pid, surveyid: sid }, function (data) {
alert('updated');
});
};
</script>
#using WebApplication2.Models
#model System.Tuple<Person, List<Survey>>
<hr />
<h1>Surveys</h1>
<input type="button" id="Coll" value="Collapse" onclick="javascript:CollapseDiv()" />
#*<p>
Number of Surveys: #Html.DisplayFor(x => Model.Item2.Count)
</p>*#
#{int i = 1;}
#foreach (var survey in Model.Item2) {
using (Html.BeginForm()) {
<h2>Survey #(i)</h2>
<p />
#Html.EditorFor(x => survey.Questions)
<button class='mybutton' type='button' data-personid="#Model.Item1.Id" data-surveyid="#survey.Id" onclick="javascript:SubmitClick()">Click Me</button>
}
i++;
<hr style="background-color:rgb(126, 126, 126);height: 5px" />
}
<hr />
The problem is that when I click the button:
I get runtime error saying that there is no definition of: "SubmitClick".
I don't see any obvious problems in your code, but given that you're handling this in a sub-optimal way, refactoring your code may solve the problem just by improving the setup.
First, don't embed your scripts directly in the view. I understand that you need to include a URL generated via one of the Razor helpers, but what I'm talking about here is using sections so that your scripts get included in a standard location in the document:
So, in your view:
#section Scripts
{
<script>
// your code here
</script>
}
And then in your layout:
<!-- global scripts like jQuery here -->
#RenderSection("Scripts", required: false)
</body>
This ensures that 1) all your JavaScript goes where it should, right before the closing body tag and 2) all your JavaScript gets run after the various global scripts that it will likely depend on (jQuery).
Second, it's usually a bad idea to define things in the global scope, such as you are doing with your SubmitClick function. If another script comes along and defines it's own SubmitClick function in the global scope, then yours gets hosed or vice versa. Instead, you want to use namespaces or closures.
Namespace
var MyNamespace = MyNamespace || {};
MyNamespace.SubmitClick = function () {
...
}
Closure
(function () {
// your code here
})();
Of course, if you use a closure like this, then you SubmitClick function truly won't exist, as it's no longer in the global scope, which brings me to...
Third, don't use the on* HTML attributes. It's far better to bind functionality to elements dynamically, for example:
(function () {
$('.mybutton').on('click', function () {
var pid = $(this).data('personid');
var sid = $(this).data('surveyid');
var url = '#Url.Action("SubmitSurvey", "Person")';
$.post(url, { personid: pid, surveyid: sid }, function (data) {
alert('updated');
});
});
})();
Now, you've got zero scope pollution and behavior is bound where behavior is defined, instead of tightly-coupling your HTML and JavaScript.

Backbone fetching url and sending templateargs to javascript template

I have been learning Backbone.js and I am using it with an app on django where two photos are displayed initially: one is the main photo and other is thumbnail of next photo. I have returned json data containing the url of mainphoto and the thumbnail photo using Tastypie in the url /api/v1/photo. So, what I've done in Backbone is that:
// MODEL
var PhotoItem = Backbone.Model.extend({
urlRoot: '/api/v1/photo',
});
var PhotoView = Backbone.View.extend({
template: _.template($('#mainimg').html()),
initialize: function() {
this.render();
},
render: function(){
var templateArgs={
photo: this.model.get('photo')
};
alert(this.model.get('photo')); // this alerts undefined
this.$el.html(this.template(templateArgs));
}
});
var photoItem = new PhotoItem({id:1});
photoItem.fetch();
var photoView = new PhotoView({model: photoItem});
In the django-template here is the javascript where the template argument is utilized for displaying the main photo.
<script type="text/template" id="mainimg">
<img class = "main-img" id="mainimgid" src = <%= photo %> alt="main photo" />
</script>
And this is the json data that is returned for photoItem with id=1:
{"next_url": "/photos/preloaded/designstyles/thumb/arabic-living(main-photo-id)-thumbnail.png",
"parent_id": "1","photo": "/photos/preloaded/designstyles/big/arabic-bedroom.png",
"photo_id": "1", "resource_uri": "", "tags": "set([Decimal('2'), Decimal('3')])", "type": "Homedesign"}
But, the image cannot be loaded. I get a javascript 404 error:
http://localhost:8000/undefined
I guess this may be due to asynchronous loading of the code. And the src for the image remains
<img class = "main-img" id="mainimgid" src = <%= photo %> alt="main photo" />
when I see on the debugging window with Chrome debugger.
What am I missing? or Where am I wrong? Can I get help?
You cannot create the view without actually receiving the information from the server. You're basically passing an empty Backbone model to the view controller, that's why model.get('photo') is returning undefined. I'd recommend you to review basic AJAX, since that's what Backbone.Model.fetch does.
Asynchronous calls return immediately to avoid freezing the user interaction. That's the reason why you should not create the view until you do get the response from the server. Right solution will be something like this:
var photoItem = new PhotoItem({id:1}), photoView;
photoItem.fetch({
success: function () {
photoView = new PhotoView({model: photoItem});
},
error: function () {
alert('Something bad happened!);
}
});

Categories

Resources