MvcFileUploader add/edit custom field - javascript

I'm using MVCFileUploader https://github.com/marufbd/MvcFileUploader
This works really well for uploading images in my MVC project and associating them with an entity.
When I try to add a title field for each image that can be edited I can't get it to work. I'm not sure if I'm approching this the correct way. I've modified the templates in _MvcFileLoad.cshtml to have the additional field. I can get the title input in the controller at each upload but I don't know how to send it back to the view using the implementation of this project.
This is _MvcFileUpload.cshtml, I've added autoUpload:true
$('##(formId)').fileupload('option', {
autoUpload: true,
maxFileSize: #Model.MaxFileSizeInBytes,
resizeMaxWidth: 1920,
resizeMaxHeight: 1200,
acceptFileTypes: #Model.FileTypes
});
I've added an input for title
<form id="#formId" action="#Model.UploadUrl" method="POST" enctype="multipart/form-data">
<div class="row fileupload-buttonbar">
<div class="col-lg-7">
<!-- The fileinput-button span is used to style the file input field as button -->
<span class="btn btn-success fileinput-button">
<i class="glyphicon glyphicon-plus"></i>
<span>Add files...</span>
<input type="file" name="files[]" multiple>
</span>
Title: <input name="title" required />
At each autoUpload I can save the title and associate it with the file and Entity in the controller. I can't get it back to the view to edit it if the user wants to. I tried to modify the template-download in _MvcFileUpload.cshtml
<!-- The template to display files available for download -->
<script id="template-download" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
<tr class="template-download fade">
<td>
<span class="preview">
{% if (file.thumbnailUrl) { %}
{% } %}
</span>
</td>
<td>
<p class="name">
{% if (file.url) { %}
<a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.thumbnailUrl?'data-gallery':''%}>{%=file.name%}</a>
{% } else { %}
<span>{%=file.name%}</span>
{% } %}
</p>
{% if (file.error) { %}
<div><span class="label label-danger">Error</span> {%=file.error%}</div>
{% } %}
</td>
<td>
Title: <input name="title" required />
</td>
<td>
<span class="size">{%=o.formatFileSize(file.size)%}</span>
</td>
<button class="btn btn-save" data-type="What to put here?" data-url="What to put here?" >
<i class="glyphicon glyphicon-save"></i>
<span>Save</span>
</button>
{% if (file.deleteUrl) { %}
<button class="btn btn-danger delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}>
<i class="glyphicon glyphicon-trash"></i>
<span>Delete</span>
</button>
<input type="checkbox" name="delete" value="1" class="toggle">
{% } else { %}
<button class="btn btn-warning cancel">
<i class="glyphicon glyphicon-ban-circle"></i>
<span>Cancel</span>
</button>
{% } %}
</td>
</tr>
{% } %}
</script>
The next issue I see is if I get the title back for editing how can send the updated input back? There's only UploadFile and DeleteFile methods to call.
In summary I'm trying to modify this so the user can upload multiple photos and edit their titles.
MvcFileUploader uses blueimp jQuery-File-Upload. I've looked at that documentation, there is something like what I'm asking for in the documentation for PHP but I couldn't get it to work with MVC.
https://github.com/blueimp/jQuery-File-Upload/wiki/PHP-MySQL-database-integration

As long as your Controller method is an HttpPost, you can add a (string title) parameter to the method and it will grab the value from the input box automatically. Otherwise, you'll need to add a data property to the javascript ajax call.
For editing the title after it's been uploaded, you should have a different page. Let them view the images, and have something that will bring up a textbox with the title in an editable field and then have a submit button there. You won't have to upload the image again, just have the ID of the image in the form.

Related

Why doesn't JavaScript onclick work when an eventlistener is used?

I'm learning JavaScript and I'm having difficulty with making a button access a function using a document.addEventListener(.
I've been able to get it to work when I place the function inside the <script> </script> tag within the html, but not successful when I use a different .js file.
Here is an example:
My js.js file:
document.addEventListener('DOMContentLoaded', function() {
// Use buttons to toggle between views
document.querySelector('#inbox').addEventListener('click', () => load_mailbox('inbox'));
document.querySelector('#sent').addEventListener('click', () => load_mailbox('sent'));
document.querySelector('#archived').addEventListener('click', () => load_mailbox('archive'));
document.querySelector('#compose').addEventListener('click', compose_email);
document.getElementById("emailSent").onclick = function() {wawa()};
});
function wawa() {
var variable = document.getElementById('compose-form').value;
console.log("WE HERE", variable)
send(variable)
}
Then my html:
{% load static %}
{% block body %}
<button class="btn btn-sm btn-outline-primary" id="inbox">Inbox</button>
<button class="btn btn-sm btn-outline-primary" id="compose">Compose</button>
<button class="btn btn-sm btn-outline-primary" id="sent">Sent</button>
<button class="btn btn-sm btn-outline-primary" id="archived">Archived</button>
<a class="btn btn-sm btn-outline-primary" href="{% url 'logout' %}">Log Out</a>
<hr>
<div id="emails-view">
</div>
<div id="compose-view">
<h3>New Email</h3>
<form id="compose-form">
<div class="form-group">
From: <input disabled class="form-control" value="{{ request.user.email }}">
</div>
<div class="form-group">
To: <input id="compose-recipients" class="form-control">
</div>
<div class="form-group">
<input class="form-control" id="compose-subject" placeholder="Subject">
</div>
<textarea class="form-control" id="compose-body" placeholder="Body"></textarea>
<input type="submit" class="btn btn-primary" id="emailSent" />
</form>
</div>
New !!!!
<div id="content">
</div>
{% endblock %}
{% block script %}
<script src="{% static 'mail/inbox.js' %}"></script>
{% endblock %}
When I push the submit button using the inspect function of the web browser nothing happens, and the console.log does not show anything.
Are you including your js file somewhere in your html? Generally this will need to be included before the function you are wanting to use is invoked. Usually in the head.

Creating input fields inside a form using JavaScript

I'm working on a quiz app and want to generate a number of input fields representing the answers based on the value that the user types.
I'm using a button named "create" to do that Using JavaScript, but when clicking the button it submits the form.
Please Check the two images below.
Input
Output
HTML Code
{% load static %}
{% block body %}
<button class="btn btn-primary new">Add a question</button>
<form class="question" method="POST" style="display: none">
{% csrf_token %}
<div class="form-group">
<label for="exampleInputEmail1">Title</label>
<input type="text" class="form-control" id="title" placeholder="Question title">
</div>
<div class="form-group" id="answers_num">
<label for="exampleInputPassword1">Number of answers</label>
<input type="number" class="form-control" id="ans_number">
<button class="create_answers">Create</button>
</div>
<div class="form-group">
{% comment %} Generated input fields {% endcomment %}
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
{% block script %}
<script src="{% static 'mcq/index.js' %}"></script>
{% endblock %}
{% endblock %}```
JS code
document.querySelector(".new").addEventListener("click", ()=> {
document.querySelector(".question").style.display = 'block';
document.querySelector("#create_answers").addEventListener("click", ()=> {
answers = this.value;
console.log(answers);
// Create input fields
for (let i = 0; i < answers; i++) {
input = document.createElement("input");
input.classList.add('form-control');
answersDiv = document.querySelector("#answers").appendChild(input);
}
})
})```
You need to explicitly set the type of the button, like
<button class="create_answers" type="button">Create</button>
in order to avoid submitting the form upon click.

How can I perform a form action with a button next to it for multiple rows using Javascript and HTML?

So, I have a html table in which I have some rows. Additional rows are added each time user buys something. For each row, there is a corresponding input form followed by Buy and Sell buttons.
What I want to achieve is that, if user wants to buy or sell something once again he can type in the desired quantity and perform his/her action by simply clicking on the buy or sell button from the index page. However, there are also Buy and Sell pages from where user also can perform his/her desired actions. I am using the form actions I used at Buy and Sell pages inside the index page.
Currently, it works only for the first row in the table. If user fills any other row than the first one and clicks buy or sell input form value returns null.
The questions I already looked into:
Multiple rows have multiple submit buttons, should I make a form for each button?
How do I implement Multiple Submit Buttons for a multi-row form?
Multiple submit buttons in an HTML form
This is how my site looks like:
Index Page
This is my index.html:
{% extends "layout.html" %}
{% block title %}
Summary
{% endblock %}
{% block main %}
<div id="alertId" class="alert alert-warning alert-dismissible fade show" role="alert" style="display:none">
<p id="alertContentId"></p>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th scope="col">Symbol</th>
<th scope="col">Shares</th>
<th scope="col">Price</th>
<th scope="col">Total</th>
<th></th>
</tr>
</thead>
<tbody>
{% for stock in ownings %}
<tr>
<td>{{ stock["symbol"].upper() }}</td>
<td>{{ stock["share_amount"] }}</td>
<td>{{ stock["price"] | usd }}</td>
<td>{{ stock["stock_total"] | usd }}</td>
<td>
<form id="action_form" method="post">
<span class="form-group">
<input id="share_quantity" autocomplete="off" autofocus class="form-control" name="shares" placeholder="Shares" type="number" min="1">
<input value="{{ stock["symbol"] }}" type="hidden" name="symbol">
</span>
<button id="btn_buy" class="btn btn-primary" type="submit" data-action="buy">Buy</button>
<button id="btn_sell" class="btn btn-primary" type="submit" data-action="sell">Sell</button>
</form>
</td>
</tr>
{% endfor %}
<tr>
<td>CASH</td>
<td></td>
<td></td>
<td>{{ cash | usd }}</td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td><strong>{{ grand_total | usd}}</strong></td>
<td></td>
</tr>
</tbody>
</table>
</div>
<script src="{{url_for('static', filename='button.js')}}"></script>
{% endblock %}
This is my buy.html:
{% extends "layout.html" %}
{% block title %}
Buy
{% endblock %}
{% block main %}
<form action="/buy" method="post">
<div class="form-group">
<input autocomplete="off" autofocus class="form-control" name="symbol" placeholder="Symbol" type="text">
</div>
<div class="form-group">
<input autocomplete="off" autofocus class="form-control" name="shares" placeholder="Shares" type="number" min="1">
</div>
<button class="btn btn-primary" type="submit">Buy</button>
</form>
{% endblock %}
This is my sell.html:
{% extends "layout.html" %}
{% block title %}
Sell
{% endblock %}
{% block main %}
<form action="/sell" method="post">
<div class="form-group">
<select class="form-control" name="symbol">
<option disabled selected value="">Symbol</option>
{% for symbol in available_symbols %}
<option value="{{ symbol["symbol"] }}">{{ symbol["symbol"].upper() }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<input autocomplete="off" class="form-control" min="0" name="shares" placeholder="Shares" type="number">
</div>
<button class="btn btn-primary" type="submit">Sell</button>
</form>
{% endblock %}
This is my button.js where I try to perform the action of the user depending on the button he/she clicks, for example if user clicks buy button then I add "/buy" action to form.
$(document).ready(function() {
$("button").click(function() {
var action = $(this).data('action'); // get button's action
// var share_quantity = document.getElementById("share_quantity").value;
if (document.getElementById("share_quantity").value == "") {
alert("enter a valid value");
}
if (action == "sell") {
document.getElementById("action_form").action = "/sell"; // change form's action to sell
// document.getElementById("alertId").style.display = "block";
// document.getElementById("alertContentId").innerHTML = "You sold " +share_quantity + " amount of shares!";
} else if (action == "buy") {
document.getElementById("action_form").action = "/buy"; // change form's action to buy
}
});
});
The problem is that all inputs, forms etc have the same ID's; the DOM doesn't like this. Because getElementById finds multiple values but can only return one, it just takes the first one (which is incorrect for all but the first rows).
I recommend putting some unique ID (stock["id"]?) and either adding a data-id attribute with that value and selecting the correct objects based on that, or extracting that value from the name itself (you have access to the button and thus to the button ID). You would need to slightly change your code (not quite sure what the jQuery selector for startswith is, but it does exist) but that shouldn't be hard.
Alternatively (though I discourage it) you could use the data from the event to find the parent form of the button clicked and extract values from there. This is a lot harder to debug and maintain.

Modelformset with dynamic form addition saves only the first form

I have two forms on one page, each with its own submit button. With JS script I can dynamically add a new formset for each of the two form. I am faced with a situation where I can add as many new forms as I want for the form that is displayed first on the page and all are saved. For the second forms list, only the first form from the formset list is saved.
template.html
<form method="post" action="">{% csrf_token %}
{{ formset_planguage.management_form }}
<div id="form_set_lang">
{% for form in formset_planguage.forms %}
{{form.non_field_errors}}
{{form.errors}}
<table class='no_error'>
{{ form }}
</table>
{% endfor %}
</div>
<input type="button" value="Add More" id="add_more_lang">
<div id="empty_form_lang" style="display:none">
<table class='no_error'>
{{ formset_planguage.empty_form }}
</table>
</div>
<input class='btn btn-primary' type="submit" name="language" value="Submit"/>
</form>
<form method="post" action="">{% csrf_token %}
{{ formset_framework.management_form }}
<div id="form_set_framework">
{% for form in formset_framework.forms %}
{{form.non_field_errors}}
{{form.errors}}
<table class='no_error'>
{{ form }}
</table>
{% endfor %}
</div>
<input type="button" value="Add More" id="add_more_framework">
<div id="empty_form_framework" style="display:none">
<table class='no_error'>
{{ formset_framework.empty_form }}
</table>
</div>
<input class='btn btn-primary' type="submit" name="framework" value="Submit"/>
</form>
<script>
$('#add_more_framework').click(function() {
var form_idx = $('#id_form-TOTAL_FORMS').val();
$('#form_set_framework').append($('#empty_form_framework').html().replace(/__prefix__/g, form_idx));
$('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1);
});
</script>
<script>
$('#add_more_lang').click(function() {
var form_idx = $('#id_form-TOTAL_FORMS').val();
$('#form_set_lang').append($('#empty_form_lang').html().replace(/__prefix__/g, form_idx));
$('#id_form-TOTAL_FORMS').val(parseInt(form_idx) + 1);
});
</script>
Your two forms are like <form method="post" action=""> so the destination is always the same page, so Django will handle both forms the same way. If in your page you handle in the POST the values of the first form, the second will be handled like it's the first form.
The best solution is to send one "big" form with all your fields named differently in the first "group" and the second "group", and read only either the first "group" or if it's empty, the second "group".
The other solution is to send the second form to a different url.

Multiple files upload - Blueimp jQuery uploader

I use a jquery plugin name "blueimp jquery file upload" - https://github.com/blueimp/jQuery-File-Upload.
I was wondering how can i add dropdown values to the database for each file when uploading multiple files.
I have used the original javascript template for uploading files and i modified it a little. It looks like this.
<script id="template-upload" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
<form id="#fileupload" action="server/php/" method="POST" enctype="multipart/form-data">
<tr class="template-upload fade">
<td>
<span class="preview"></span>
</td>
<td>
<p class="name">{%=file.name%}</p>
<strong class="error text-danger"></strong>
</td>
<td>
<p class="size">Processing...</p>
<div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
<div class="progress-bar progress-bar-success" style="width:0%;">/div>
</div>
</td>
<td>
<label class="title">
<select name="title[]" >
<option value="val1">val1</option>
<option value="val2">val2</option>
</select>
</label>
<label class="description">
<span>Description:</span><br>
<input name="description[]" class="form-control">
</label>
{% if (!i && !o.options.autoUpload) { %}
<button class="btn btn-primary start upload-file" disabled>
<i class="glyphicon glyphicon-upload"></i>
<span>Start</span>
</button>
{% } %}
{% if (!i) { %}
<button class="btn btn-warning cancel">
<i class="glyphicon glyphicon-ban-circle"></i>
<span>Cancel</span>
</button>
{% } %}
</td>
</tr>
</form>
{% } %}
</script>
I am trying to make it to work. I spend a lot of time today but don't want to gave up. If someone had expericne with this, please help me, give me direction.
i have found this but i cant figure it out how to make it work
https://github.com/blueimp/jQuery-File-Upload/wiki/How-to-submit-additional-Form-Data
Thanks
Best Regards,
Darko
See server/php/UploadHandler.php in function handle_file_upload try connect to db and save files details in database

Categories