Can any body give example to save the multipart form by using backbone js model?
How to combine the form data with file data and save to model
I am setting the model attributes and how to include the file data in the attributes. I adapted the code from one of the site to Forc Backbone to save an attribute as a file. I could not relate it to my form
<form enctype="multipart/form-data">
<input type="file" name="ImageData">
<input type="text" name="UserName">
</form>
Model
User = Backbone.Model.extend({
readAvatar : function (file, callback) {
var reader = new FileReader(); // File API object for reading a file locally
reader.onload = (function (theFile, self) {
return function (e) {
// Set the file data correctly on the Backbone model
self.set({avatar_file_name : theFile.name, avatar_data : fileEvent.target.result});
// Handle anything else you want to do after parsing the file and setting up the model.
callback();
};
})(file, this);
reader.readAsDataURL(file); // Reads file into memory Base64 encoded
}
attribute : function(attr) {
return Object.defineProperty(this.prototype, attr, {
get: function() {
return this.get(attr);
},
set: function(value) {
var attrs;
attrs = {};
attrs[attr] = value;
return this.set(attrs);
}
});
};
});
var form_data = form.serializeArray();
View
this.model.data = form_data;
var profiledata;
if (window.FormData) {
profiledata = new FormData();
console.log(profiledata);
}
if (profiledata) {
jQuery.each($('#ImageData')[0].files, function(i, file) {
//reader.readAsDataURL(file);
profiledata.append("ImageData[]", file);
});
}
this.model.ImageData = profiledata;
//and save the data
this.model.save
Rather than handling the FileReader logic in the model, I've been managing that in the view.
Check this out:
<form enctype="multipart/form-data">
<input type="file" name="ImageData">
<input type="text" name="UserName">
<button>Submit</button>
</form>
View:
var FormView = Backbone.View.extend({
events: {
"submit form" : "submit",
"change input[type=file]" : "encodeFile"
},
render: function () {
var content = this.template();
this.$el.html(content);
return this;
},
encodeFile: function (event) {
var file = event.currentTarget.files[0];
var reader = new FileReader();
reader.onload = function (fileEvent) {
this.model.set({
avatar_data: fileEvent.target.result // file name is part of the data
});
}.bind(this)
reader.onerror = function () {
console.log("error", arguments)
}
reader.readAsDataURL(file);
},
submit: function (event) {
event.preventDefault();
this.model.set({ UserName: $('input[name=UserName]').val() });
this.model.save();
}
});
Related
I'm working on uploading multiple files using Laravel and Vue 3. File uploading is doing fine until I added a select tag in the form for the category. I put the category and files into one object so I can pass only 1 parameter. Now in TestController I can get the value of category but giving me error in files.
I need to:
Pass category and files
Read category and files so I can move and save info to database
test.vue
<form #submit.prevent="upload" enctype="multipart/form-data">
<!-- added this tag for category -->
<select v-model="category">
<option v-for="type in categories" :key="type.id" :value="type.id">
{{ type.name }}
</option>
</select>
<input type="file" multiple #change="fileChange">
<button type="submit">Upload</button>
</form>
<script>
import useTest from "../composables/test.js"
import { onMounted } from 'vue'
export default {
setup() {
const { categories, getCategories, uploadFile } = useTest()
onMounted(getCategories)
const attachments = []
const category = 1 // added for category
const upload = async () => {
// const formData = new FormData // without category
// with category, I put inside an object so I can pass only 1 parameter
const form = {
category: category.value,
files: new FormData,
}
// loop to append
Object.keys(attachments).forEach(
// key => formData.append(key, attachments[key]) // without category
key => form.files.append(key, attachments[key]) // with category
)
// call from composable
await uploadFile(form)
}
return {
categories,
category,
upload,
}
},
}
</script>
composable: test.js
import { ref } from 'vue'
import axios from 'axios'
export default function useTest() {
const categories = ref([])
const getCategories = async () => {
let response = await axios.get("/api/fileUpload/")
categories.value = response.data.categories
}
const uploadFile = async (form) => {
// METHOD IS INSIDE TRY CATCH BLOCK
const config = {headers: { 'content-type': 'multipart/form-data' }}
// let response = await axios.post("/api/fileUpload/", form, config)
let response = await axios.post("/api/fileUpload/", form)
console.log(response);
}
return {
categories,
getCategories,
uploadFile,
}
}
TestController
public function store(Request $request)
{
// $uploadFiles = $request; // without category
$uploadFiles = $request['files']; // with category
$uploadFiles = $request['category'];
error_log($uploadFiles);
// error here: Attempt to read property \"files\" on array
foreach ($uploadFiles->file as $file) {
error_log('here');
error_log($file->getClientOriginalName());
error_log($file->getClientOriginalExtension());
error_log($file->getSize());
error_log($file->getMimeType());
error_log(date("m/d/Y H:i:s.",filemtime($file)));
error_log('---------------------');
}
return response()->json(['status'=>'success'], status: 200);
}
I've found a video from SharePointTech that explains how to change a textfield to a dropdown list on a List Form using data from open API. I'm trying to recreate it, but I'm hitting a roadblock with the new SharePoint Online. Instead of using "Country/Region", I created a new custom list with Company_Name. I took the person's code and made little changes that made a reference to "WorkCountry". When I save the changes (stop editing), the changes do not reflect and I get the same textfield. I had to use SharePoint Designer 2013 to create a new TestNewForm for new entry. Has anyone been able to reproduce this in SharePoint 2013 Designer? If so, would you be able an example?
I use jQuery's ajax method.
Updated code for your reference(you need to change the list name to your list name,InternalName is also):
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js">
</script>
<script>
var demo = window.demo || {};
demo.nodeTypes = {
commentNode: 8
};
demo.fetchCountries = function ($j) {
$.ajax({
url: _spPageContextInfo.siteAbsoluteUrl + "/_api/web/lists/getbytitle('Company_Name')/items",
type: "get",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
$j('table.ms-formtable td.ms-formbody').contents().filter(function () {
return (this.nodeType == demo.nodeTypes.commentNode);
}).each(function (idx, node) {
if (node.nodeValue.match(/FieldInternalName="Country_x002f_Region"/)) {
// Find existing text field (<input> tag)
var inputTag = $(this).parent().find('input');
// Create <select> tag out of retrieved countries
var optionMarkup = '<option value="">Choose one...</option>';
$j.each(data.d.results, function (idx, company) {
optionMarkup += '<option>' + company.Title + '</option>';
});
var selectTag = $j('<select>' + optionMarkup + '</select>');
// Initialize value of <select> tag from value of <input>
selectTag.val(inputTag.val());
// Wire up event handlers to keep <select> and <input> tags in sync
inputTag.on('change', function () {
selectTag.val(inputTag.val());
});
selectTag.on('change', function () {
inputTag.val(selectTag.val());
});
// Add <select> tag to form and hide <input> tag
inputTag.hide();
inputTag.after(selectTag);
}
});
},
error: function (data) {
console.log(data)
}
});
}
if (window.jQuery) {
jQuery(document).ready(function () {
(function ($j) {
demo.fetchCountries($j);
})(jQuery);
});
}
</script>
My source list:
Test result:
Updated:
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js">
</script>
<script>
var demo = window.demo || {};
demo.nodeTypes = {
commentNode: 8
};
demo.fetchCountries = function ($j) {
$.ajax({
url: 'https://restcountries.eu/rest/v1/all',
type: "get",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
$j('table.ms-formtable td.ms-formbody').contents().filter(function () {
return (this.nodeType == demo.nodeTypes.commentNode);
}).each(function (idx, node) {
if (node.nodeValue.match(/FieldInternalName="Country_x002f_Region"/)) {
// Find existing text field (<input> tag)
var inputTag = $(this).parent().find('input');
// Create <select> tag out of retrieved countries
var optionMarkup = '<option value="">Choose one...</option>';
$j.each(data, function (idx, company) {
optionMarkup += '<option>' + company.name + '</option>';
});
var selectTag = $j('<select>' + optionMarkup + '</select>');
// Initialize value of <select> tag from value of <input>
selectTag.val(inputTag.val());
// Wire up event handlers to keep <select> and <input> tags in sync
inputTag.on('change', function () {
selectTag.val(inputTag.val());
});
selectTag.on('change', function () {
inputTag.val(selectTag.val());
});
// Add <select> tag to form and hide <input> tag
inputTag.hide();
inputTag.after(selectTag);
}
});
},
error: function (data) {
console.log(data)
}
});
}
if (window.jQuery) {
jQuery(document).ready(function () {
(function ($j) {
demo.fetchCountries($j);
})(jQuery);
});
}
</script>
The difference in API will not have a great effect, the key is here '$ j.each (data, function (idx, company) {'. The structure of the return value of different APIs are different, you need to find useful data in return value.
Creating a map with markers displayed on it. When clicking a marker, this one has to display a Popup. I extended the L.Popup like this
L.InfrastructurePopup = L.Popup.extend({
options: {
template : "<form id='popup-form'>\
<div>\
<label for='problem'>Problem</label>\
<textarea id='problem' rows='4' cols='46' placeholder='Type your text here'></textarea>\
</div>\
<div>\
<label for='solution'>Solution</label>\
<textarea id='solution' rows='4' cols='46' placeholder='Type your text here'></textarea>\
</div>\
<button id='button-submit' class='btn btn-primary' type='button'>Submit</button>\
</form>",
},
setContent: function () {
this._content = this.options.template;
this.update();
return this;
},
initializeForm(layer, callback)
{
var problem = L.DomUtil.get('problem');
problem.textContent = layer.options.problem ? layer.options.problem : "";
problem.addEventListener('change', (e) =>
{
layer.options.problem = problem.value;
});
var solution = L.DomUtil.get('solution');
solution.textContent = layer.options.solution ? layer.options.solution : "";
solution.addEventListener('change', (e) =>
{
layer.options.solution = solution.value;
});
var buttonSubmit = L.DomUtil.get('button-submit');
buttonSubmit.addEventListener('click', (e) =>
{
callback(layer);
});
}
});
L.infrastructurePopup = function (options, source)
{
return new L.InfrastructurePopup(options, source);
};
I linked it into a custom Marker called InfrastructureMarker that has one and only popup , a InfrastructurePopup. So when it calls the openPopup() function it loads the popup on the map [ map.addLayer(popup) ] and give me the correct datas thanks to method initializeForm() that I call after the addLayer(popup) method.
L.Map.include({
openInfrastructurePopup: function (layer, callback)
{
this.closePopup();
layer._popup._isOpen = true;
this.addLayer(layer._popup);
layer._popup.initializeForm(layer, callback);
}
});
L.InfrastructureMarker = L.Marker.extend({
openPopup: function (callback)
{
if (this._popup && this._map && !this._map.hasLayer(this._popup))
{
this._popup.setLatLng(this._latlng);
this._map.openInfrastructurePopup(this, callback);
}
return this;
},
togglePopup: function (callback)
{
if (this._popup)
{
if (this._popup._isOpen)
{
this._popup._isOpen = false;
this.closePopup();
}
else
{
this.openPopup(callback);
}
}
return this;
},
bindPopup: function (callback, options)
{
var anchor = L.point(this.options.icon.options.popupAnchor || [0, 0]);
anchor = anchor.add(L.Popup.prototype.options.offset);
if (options && options.offset)
{
anchor = anchor.add(options.offset);
}
options = L.extend({offset: anchor}, options);
if (!this._popupHandlersAdded)
{
this
.on('click', () => {this.togglePopup(callback)}, this)
.on('remove', this.closePopup, this)
.on('move', this._movePopup, this);
this._popupHandlersAdded = true;
}
this._popup = new L.infrastructurePopup(options, this).setContent();
return this;
},
});
L.infrastructureMarker = function (latlng, options)
{
return new L.InfrastructureMarker(latlng, options);
};
But if I decide to click on one marker, then on another one without closing the first one, it loads the template, but initializeForm(callback) doesn't change the datas. I checked all the datas to know if it was empty or something but everything worked, I absolutely don't know where the problem is. I suppose the popup is not yet set on the DOM before my L.DomUtils.get fire but I shouldn't see undefined elements in console.log when I'm getting them.
I actually found what was happening :
Actually, when the L.map calls its closePopup function , it destroys the layer.
So after that, it creates a new one to display. BUT the remaining HTML from the previous kind of still exists.
So I finally bound exact same Ids to two HTML tags. Heresy !
My solution became what's next :
L.InfrastructurePopup = L.Popup.extend({
setContent: function (layer)
{
var template = "<form id='popup-form'>\
<div>\
<label for='problem'>Problème Identifié</label>\
<textarea id='" + layer._leaflet_id + "-problem' rows='4' cols='46' placeholder='Type your text here'></textarea>\
</div>\
<div>\
<label for='solution'>Solution Proposée</label>\
<textarea id='" + layer._leaflet_id + "-solution' rows='4' cols='46' placeholder='Type your text here'></textarea>\
</div>\
<button id='" + layer._leaflet_id + "-button-submit' class='btn btn-primary' type='button'>Submit</button>\
</form>";
this._content = template;
this.update();
return this;
},
initializeForm: function(layer, callback)
{
console.log(L.DomUtil.get(layer._leaflet_id+'-problem'));
var problem = L.DomUtil.get(layer._leaflet_id + '-problem');
problem.textContent = layer.options.problem ? layer.options.problem : "";
problem.addEventListener('change', (e) =>
{
layer.options.problem = problem.value;
});
var solution = L.DomUtil.get(layer._leaflet_id + '-solution');
solution.textContent = layer.options.solution ? layer.options.solution : "";
solution.addEventListener('change', (e) =>
{
layer.options.solution = solution.value;
});
var buttonSubmit = L.DomUtil.get(layer._leaflet_id + '-button-submit');
buttonSubmit.addEventListener('click', (e) =>
{
callback(layer);
});
}
});
L.infrastructurePopup = function (options, source)
{
return new L.InfrastructurePopup(options, source);
};
Calling setContent when creating my InfrastructurePopup with the layer_id and set it into my template made it work.
I got : '97-problem' or '99-problem' and '97-solution' or '99-solution
The Excel sheet want to read while it upload on a button click in MVC5.The uploaded excel file name is passed into action using AJAX method.Here the file variable get null value in posted method.
Here how can pass selected file as HttpPostedFileBase in the below ajax method.
`
<input style="display:none" type="file" id="fileupload1" />
<button type="button" onclick='$("#fileupload1").click()'>UPLOAD FROM EXCEL</button>
<span style="display:none" id="spnName"></span>
$(function () {$("#fileupload1").change(function () {
$("#spnName").html($("#fileupload1").val().substring($("#fileupload1").val().lastIndexOf('\\') + 1));
var file = $("#spnName").html();
$.ajax({
url: "UploadExcelForContractStaff",
type: 'POST',
data: JSON.stringify({ file: file }),
dataType: 'json',
contentType: "application/json; charset=utf-8",
success: function (data) {
}
});
});
});`
[AcceptVerbs(HttpVerbs.Post)]
public string UploadExcelForContractStaff(HttpPostedFileBase uploadFile)
{
StringBuilder strValidations = new StringBuilder(string.Empty);
try
{
if (uploadFile.ContentLength > 0)
{
string filePath = Path.Combine(HttpContext.Server.MapPath("../Uploads"),
Path.GetFileName(uploadFile.FileName));
uploadFile.SaveAs(filePath);
DataSet ds = new DataSet();
//A 32-bit provider which enables the use of
string ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + filePath + ";Extended Properties=Excel 12.0;";
using (OleDbConnection conn = new System.Data.OleDb.OleDbConnection(ConnectionString))
{
conn.Open();
using (DataTable dtExcelSchema = conn.GetSchema("Tables"))
{
string sheetName = dtExcelSchema.Rows[0]["TABLE_NAME"].ToString();
string query = "SELECT * FROM [" + sheetName + "]";
OleDbDataAdapter adapter = new OleDbDataAdapter(query, conn);
//DataSet ds = new DataSet();
adapter.Fill(ds, "Items");
if (ds.Tables.Count > 0)
{
if (ds.Tables[0].Rows.Count > 0)
{
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
//Now we can insert this data to database...
}
}
}
}
}
}
}
catch (Exception ex) { }
return "";
}
I got solution. changed code like
<form enctype="multipart/form-data" id="frmUplaodFileAdd">
#Html.AntiForgeryToken()
<input style="display:none" type="file" id="fileupload1" />
<button type="button" onclick='$("#fileupload1").click()'>UPLOAD FROM EXCEL</button>
<span style="display:none" id="spnName"></span>
</form>
$.ajax({
url: "UploadFile", //Server script to process data
type: 'POST',
async: false,
xhr: function () { // Custom XMLHttpRequest
var myXhr = $.ajaxSettings.xhr();
if (myXhr.upload) { // Check if upload property exists
myXhr.upload.addEventListener('progress',
progressHandlingFunction, false); // For handling the progress of the upload
}
return myXhr;
},
data: formData,
//Options to tell jQuery not to process data or worry about content-type.
cache: false,
contentType: false,
processData: false,
success: function (data) { }
});
[HttpPost]
public ActionResult UploadFile(HttpPostedFileBase file)
{return Json();
}
I've worked on this but couldn't fully figure out.
Basically, what I need is to upload 2 or more files separately (only on demand one by one, not all files at once) using Ajax upload. Currently, I have 2 file inputs but somehow, the JavaScript code always uploads the first file input (the one inside "formContentProperty").
Here is my HTML code:
<div>
<form enctype="multipart/form-data" id="formContentProperty">
<input id="fileContentProperty" type="file" name="fileContentProperty" />
<a id="uploadbuttonContentProperty" href="javascript:void(0)">
<span>Upload 1</span>
</a>
</form>
<progress></progress>
</div>
<div>
<form enctype="multipart/form-data" id="formContentPreviewImage">
<input id="fileContentPreviewImage" type="file" name="fileContentPreviewImage"/>
<a id="uploadbuttonContentPreviewImage" href="javascript:void(0)">
<span>Upload 2</span>
</a>
</form>
<progress></progress>
</div>
Here is my JavaScript code:
$('#uploadbuttonContentProperty').click(function () {
return UpdoadFile('formContentProperty', 'divUploadContentPropertyResultMessage');
});
$('#uploadbuttonContentPreviewImage').click(function () {
return UpdoadFile('formContentPreviewImage', 'divUploadContentPreviewImageResultMessage');
});
function UpdoadFile(formElementId, divMessageElementId) {
var formData = new FormData($('form')[0]);
$.ajax({
url : '<%= base.AjaxUploadHandlerPath %>', //Server script to process data
type : 'POST',
xhr : function() { // Custom XMLHttpRequest
var myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){ // Check if upload property exists
myXhr.upload.addEventListener('progress',progressHandlingFunction, false); // For handling the progress of the upload
}
return myXhr;
},
//beforeSend: beforeSendHandler,
success : function(response) {
var obj = $.parseJSON(response);
$('#' + divMessageElementId).html(obj.ResultMessage);
},
//error : errorHandler,
data : formData,
//Options to tell jQuery not to process data or worry about content-type.
cache : false,
contentType : false,
processData : false
});
};
function progressHandlingFunction(e){
if(e.lengthComputable)
$('progressContentProperty').attr({ value: e.loaded, max: e.total });
}
I'd really appreciate any help.
To upload files using ajax file upload
<script>
function uploadFiles()
{
var files = $('#previewFile')[0].files;
var totalFiles = files.length
for(var i=0; i < totalFiles; i++)
{
var formData = new FormData();
formData.append("previewFile",files[i]);
doAjaxFileUpload("/storeTempFile.do", formData,function(data)
{
data = eval(data);
if (data.result=="success")
{
alert("File uploaded successfully");
}
else
{
alert("Error occured : "+data);
}
},
function(data)
{
alert("Error occured : "+data);
});
}
}
function doAjaxFileUpload(actionURL,params,callbackSuccessFunction,callbackFailureFunction)
{
$.ajax(
{
url: actionURL,
type: "POST",
data: params,
processData: false,
contentType: false,
error: callbackFailureFunction,
success : callbackSuccessFunction
});
}
</script>