I have a rails application that allows users to attach multiple files and detach files using jquery. However, the problem is you can select multiple files but only the last file selected gets uploaded. Not all files that were selected. Think it's something with my javascript code.
below is an image of what i am talking about
enter image description here
zen_support/zen_upload.js
$(function() {
files = void 0;
setRemove = void 0;
uploadfile = void 0;
files = [];
$('#upload_button').click(function(event) {
return $('#file_input').trigger('click');
});
$('#file_input').change(function(event) {
var file;
file = void 0;
file = event.target.files[0];
files.push(file);
return uploadfile(files.length - 1, file);
});
uploadfile = function(index, file) {
var fileitem, formData;
fileitem = void 0;
formData = void 0;
formData = new FormData;
formData.append('file', file);
fileitem = '<li class=\'file-item success\'> <div class=\'active\'> <span class=\'remove\'>×</span> <span>' + file.name + '</span> </div> <div class=\'lds-ellipsis\'><div></div><div></div><div></div><div></div></div> </li>';
$('#filelist').append(fileitem);
return setRemove();
};
return setRemove = function() {
$('.remove').unbind();
return $('.remove').click(function() {
var index;
index = void 0;
index = $(this).parent().parent().index();
files.splice(index, 1);
return $('.file-item').eq(index).remove();
});
};
});
_edit.html.haml
= render 'show'
= javascript_include_tag "zen_support/zen_upload.js"
.row
.col-12
%ZenForm{ path: zen_support_urls.ticket_path, id: #zendesk_ticket.id, method: :put, :multipart => true, data: { remote: true } }
.row
.col-md-4
%button.fileUpload.btn.btn-default#upload_button{type: "button"}
Attach File
%input.upload#file_input{:name => "attachments[]", multiple: true, :type => "file"}
.col-md-8
%ul#filelist
- #zendesk_ticket.comments.each do | comment |
= render "files", comment: comment
%ZenTextArea#comment{ label: "Comments", placeholder: "Add any comments you think will help us address your issue.", error: #zendesk_ticket.errors&.dig(:comment) }
Related
I am using a 'Custom Datatable' solution in order to modify picklist values within a datatable. Project code may be referenced here:
https://live.playg.app/play/picklist-in-lightning-datatable
I have made changes so that I can retrieve data from the custom object: Payment__c, and I am attempting modify the picklist values for the Payment_Status__c field. My 'debugging' method has been to create numerous console.log statements to verify data during the updating process. Picklist values are currently hardcoded (have not figured out how to dynamically pull from SF yet). Inline edit of individual cells works fine, and I am able to save those values as well (though changes are not reflected until I perform a manual page refresh). Picklist selection is working, but I am unable to save the currently selected picklist value in the datatable.
I believe that the intended trigger event for picklist selection changes--'valueselect', is not being fired, and the handleSelection method is not receiving this event when a new picklist selection is made.
The lightning component used on Salesforce is c-customDatatableDemo:
customDatatableDemo.js
import { LightningElement, track, wire } from 'lwc';
import getPayments from '#salesforce/apex/PaymentController.getPayments';
import saveRecords from '#salesforce/apex/PaymentController.saveRecords';
import { updateRecord } from 'lightning/uiRecordApi';
import { refreshApex } from '#salesforce/apex';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
export default class CustomDatatableDemo extends LightningElement {
#track data = [];
//have this attribute to track data changed
//with custom picklist or custom lookup
#track draftValues = [];
#track lastSavedData = [];
connectedCallback() {
this.columns = [
{
label: 'Name',
fieldName: 'Name',
editable: false
}, {
label: 'Invoice Number',
fieldName: 'Invoice_Number__c',
editable: true
}, {
label: 'Invoice Amount',
fieldName: 'Invoice_Amount__c',
type: 'currency',
editable: true
}, {
label: 'Invoice Date',
fieldName: 'Invoice_Date__c',
type: 'date',
editable: true
}, {
label: 'Payment Status',
fieldName: 'Payment_Status__c',
type: 'picklist',
typeAttributes:
{
placeholder: 'Choose Status',
options: [
{ label: 'Needs to Be Paid', value: 'Needs to Be Paid' },
{ label: 'Issued', value: 'Issued' },
{ label: 'Voided', value: 'Voided' },
] // List of Payment Status picklist options
, value: {fieldName: 'Payment_Status__c' } // default value for picklist
, context: {fieldName: 'Id' } // binding Payment Id with context variable to be returned back
}
},
{
label: 'Description', fieldName: 'Work_Description__c', type: 'text', editable: true
}];
// Get Payments data
getPayments()
.then(result => {
this.data = result;
this.error = undefined;
})
.catch(error => {
this.error = error;
this.data = undefined;
})
// Save last saved copy
this.lastSavedData = JSON.parse(JSON.stringify(this.data));
}
updateDataValues(updateItem) {
console.log('START--updateDataValues()');
let copyData = [... this.data];
copyData.forEach(item => {
if (item.Id === updateItem.Id) {
for (let field in updateItem) {
console.log('updateDataValues() item.Id = ' + JSON.stringify(updateItem.Id));
console.log('updateItem[field] = ' + JSON.stringify(updateItem[field]));
item[field] = updateItem[field];
console.log('UPDATED--item[field] = ' + updateItem[field]);
}
}
});
//write changes back to original data
this.data = [...copyData];
console.log('this.data = ' + JSON.stringify(this.data));
let tempData = [...this.data];
//console.log('tempData = ' + JSON.stringify(tempData));
console.log('END--updateDataValues()');
}
updateDraftValues(updateItem) {
console.log('START--updateDraftValues()');
console.log('stringify draft updateItem = ' + JSON.stringify(updateItem));
let draftValueChanged = false;
let copyDraftValues = [...this.draftValues];
//store changed value to do operations
//on save. This will enable inline editing &
//show standard cancel & save button
let i = 0;
copyDraftValues.forEach(item => {
if (item.Id === updateItem.Id) {
i++;
console.log('i = ' + i);
for (let field in updateItem) {
console.log(i + '. UpdateDraftValues--item id if selected...item Id = ' + item.Id + ' & item value = ' + item.value);
item[field] = updateItem[field];
console.log('item[field] = ' + updateItem[field]);
}
draftValueChanged = true;
console.log('draftValueChanged = TRUE');
}
});
//draftValueChanged = true;
if (draftValueChanged) {
console.log('YESdraftValueChanged');
console.log('copyDraftValues = ' + JSON.stringify(copyDraftValues));
this.draftValues = [...copyDraftValues];
//console.log('draftValues = ' + JSON.stringify(draftValues));
} else {
console.log('NOdraftValue!Changed');
this.draftValues = [...copyDraftValues, updateItem];
let testDraftValues = {... this.draftValues};
console.log('JSON.stringify(testDraftValues) = ' + JSON.stringify(testDraftValues));
}
console.log('STOP--updateDraftValues()')
}
//listener handler to get the context and data
//updates datatable
picklistChanged(event) {
console.log('START--picklistChanged()');
console.log('EVENT type - ' + event.type);
event.stopPropagation();
let dataReceived = event.detail.data;
let updatedItem = { ...dataReceived };
console.log('picklistChanged()...updatedItem = ' + JSON.stringify(updatedItem));
this.updateDraftValues(updatedItem);
this.updateDataValues(updatedItem);
/* console.log('event.value = ' + event.value);
this.value = event.target.value;
event.stopPropagation();
let dataReceived = event.detail.data;
let updatedItem = { ...dataReceived };
console.log('updatedItem.context ' + updatedItem.context);
console.log('updatedItem.value ' + updatedItem.value);
console.log('updatedItem = ' + JSON.stringify(updatedItem));
this.updateDraftValues(updatedItem);
this.updateDataValues(updatedItem);
console.log('picklistChanged() = ' + JSON.stringify(updatedItem)); */
console.log('STOP--picklistChanged()');
}
handleSelection(event) {
console.log('START--handleSelection()');
this.updateDraftValues(event.detail.draftValues[0]);
console.log('this.updateDraftValues(event.detail.draftValues[0]);')
/* event.stopPropogation();
let dataReceived = event.detail.data;
let updatedItem = { ...dataReceived };
this.updateDraftValues(updatedItem);
this.updateDraftValues(updatedItem); */
console.log('STOP--handleSelection() = ' + JSON.stringify(updatedItem));
}
//handler to handle cell changes & update values in draft values
handleCellChange(event) {
console.log('START--handleCellChange()');
console.log('handleCellChange');
this.updateDraftValues(event.detail.draftValues[0]);
console.log('handleCellChange value = ' + JSON.stringify(this.updateDraftValues));
console.log('END--handleCellChange()');
}
handleSave(event) {
if (event.type === 'picklistchanged'){
}
console.log('START--handleSave');
console.log('Updated items = ', this.draftValues);
// save last saved copy
this.lastSavedData = JSON.parse(JSON.stringify(this.data));
console.log('this.lastSavedData = ' + JSON.stringify(this.lastSavedData));
this.fldsItemValues = event.detail.draftValues;
console.log('this.fldsItemValues = ' + JSON.stringify(this.fldsItemValues));
const inputsItems = this.fldsItemValues.slice().map(draft => {
const fields = Object.assign({}, draft);
console.log('JSON.stringify() fields ' + JSON.stringify(fields));
return { fields };
});
// Show toast after successful update
const promises = inputsItems.map(recordInput => updateRecord(recordInput));
Promise.all(promises).then(res => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'Records Updated Successfully!!',
variant: 'success'
})
);
this.fldsItemValues = [];
return this.refresh();
}).catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error',
message: 'An Error Occured!!',
variant: 'error'
})
);
}).finally(() => {
// Clear draft values
this.draftValues = [];
});
// Refresh the window after successful save
//window.open('url','_self');
//document.location.reload(true);
//cmp.find("table-component-id").set("v.draftValues", null);
console.log('END--handleSave');
}
handleCancel(event) {
//remove draftValues & revert data changes
this.data = JSON.parse(JSON.stringify(this.lastSavedData));
this.draftValues = [];
}
async refresh() {
console.log('async refresh');
await refreshApex(this.data);
//this.connectedCallback();
}
}
customDatatableDemo.html
<template>
<lightning-card title="Invoicing" icon-name="custom:custom17">
<div class="slds-var-m-around_medium">
<template if:true={data}>
<c-custom-data-table
object-api-name="Payment__c"
key-field="Id"
data={data}
value=""
show-row-number-column
columns={columns}
onpicklistchanged={picklistChanged}
onvalueselect={handleSelection}
draft-values={draftValues}
oncellchange={handleCellChange}
onsave={handleSave}
oncancel={handleCancel}>
</c-custom-data-table>
<template if:true={data.error}></template>
</template>
</div>
</lightning-card>
<p>Selected value is: {value}</p>
</template>
customDataTable.js
import LightningDatatable from 'lightning/datatable';
//import the template so that it can be reused
import DatatablePicklistTemplate from './picklist-template.html';
import { loadStyle } from 'lightning/platformResourceLoader';
import CustomDataTableResource from '#salesforce/resourceUrl/CustomDataTable';
export default class CustomDataTable extends LightningDatatable {
static customTypes = {
picklist: {
template: DatatablePicklistTemplate,
typeAttributes: ['label', 'placeholder', 'options', 'value', 'context'],
},
};
constructor() {
super();
Promise.all([
loadStyle(this, CustomDataTableResource),
]).then(() => {})
}
}
picklist-template.html (Same folder as customDataTable)
<template>
<c-datatable-picklist label={typeAttributes.label} value={typeAttributes.value}
placeholder={typeAttributes.placeholder} options={typeAttributes.options} context={typeAttributes.context}>
</c-datatable-picklist>
</template>
datatablePicklist.js
import { LightningElement, api, track } from 'lwc';
export default class DatatablePicklist extends LightningElement {
#api label;
#api placeholder;
#api options;
#api value;
#api context;
handleChange(event) {
//show the selected value on UI
this.value = event.detail.value;
//fire event to send context and selected value to the data table
this.dispatchEvent(new CustomEvent('picklistchanged', {
composed: true,
bubbles: true,
cancelable: true,
detail: {
data: { context: this.context, value: this.value }
}
}));
}
}
datatablePicklist.html
<template>
<div class="picklist-container">
<lightning-combobox name="picklist" label={label} value={value} placeholder={placeholder} options={options}
onchange={handleChange}></lightning-combobox>}
</div>
</template>
lwcEditSaveRow.js
import { LightningElement, wire, track } from 'lwc';
import getAccounts from '#salesforce/apex/lwcEditSaveRowCtrl.getAccounts';
import { updateRecord } from 'lightning/uiRecordApi';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { refreshApex } from '#salesforce/apex';
const columns = [
{
label: 'Name',
fieldName: 'Name',
type: 'text',
}, {
label: 'Phone',
fieldName: 'Phone',
type: 'phone',
editable: true,
}, {
label: 'Industry',
fieldName: 'Industry',
type: 'text',
editable: true,
}, {
label: 'Type',
fieldName: 'Type',
type: 'text',
editable: true
}, {
label: 'Description',
fieldName: 'Type',
type: 'text',
editable: true
}
];
export default class LwcEditSaveRow extends LightningElement {
columns = columns;
#track accObj;
fldsItemValues = [];
#wire(getAccounts)
cons(result) {
this.accObj = result;
if (result.error) {
this.accObj = undefined;
}
};
saveHandleAction(event) {
this.fldsItemValues = event.detail.draftValues;
const inputsItems = this.fldsItemValues.slice().map(draft => {
const fields = Object.assign({}, draft);
return { fields };
});
const promises = inputsItems.map(recordInput => updateRecord(recordInput));
Promise.all(promises).then(res => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'Records Updated Successfully!!',
variant: 'success'
})
);
this.fldsItemValues = [];
return this.refresh();
}).catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error',
message: 'An Error Occured!!',
variant: 'error'
})
);
}).finally(() => {
this.fldsItemValues = [];
});
}
async refresh() {
await refreshApex(this.accObj);
}
}
lwcEditSaveRow.html
<template>
<lightning-card>
<div class="slds-m-around_medium">
<h3 class="slds-text-heading_medium"><lightning-icon icon-name="custom:custom84" size="small"></lightning-icon> <strong style="color:#270086; font-size:13px; margin-right:5px;"> How to inline Edit/Save Rows With Lightning Datatable in Lightning Web Component (LWC) </strong></h3>
<br/><br/>
<template if:true={accObj.data}>
<lightning-datatable key-field="Id"
data={accObj.data}
columns={columns}
onsave={saveHandleAction}
draft-values={fldsItemValues}
hide-checkbox-column
show-row-number-column>
</lightning-datatable>
</template>
<br/>
<br/>
<!--Start RelatedTopics Section-->
<div style="border:1px #ddd solid; padding:10px; background:#eee; margin:40px 0;">
<p data-aura-rendered-by="435:0"><img src="https://www.w3web.net/wp-content/uploads/2021/05/thumbsUpLike.png" width="25" height="25" style="vertical-align:top; margin-right:10px;" data-aura-rendered-by="436:0"><strong data-aura-rendered-by="437:0"><span style="font-size:16px; font-style:italic; display:inline-block; margin-right:5px;">Don't forget to check out:-</span>An easy way to learn step-by-step online free Salesforce tutorial, To know more Click <span style="color:#ff8000; font-size:18px;" data-aura-rendered-by="442:0">Here..</span></strong></p>
<br/><br/>
<p data-aura-rendered-by="435:0"><img src="https://www.w3web.net/wp-content/uploads/2021/07/tickMarkIcon.png" width="25" height="25" style="vertical-align:top; margin-right:10px;" data-aura-rendered-by="436:0"><strong data-aura-rendered-by="437:0"><span style="font-size:17px; font-style:italic; display:inline-block; margin-right:5px; color:rgb(255 128 0);">You May Also Like →</span> </strong></p>
<div style="display:block; overflow:hidden;">
<div style="width: 50%; float:left; display:inline-block">
<ul style="list-style-type: square; font-size: 16px; margin: 0 0 0 54px; padding: 0;">
<li>How to get selected checkbox value in lwc</li>
<li>how to display account related contacts based on AccountId in lwc</li>
<li>how to create lightning datatable row actions in lwc</li>
<li>how to use if and else condition in lwc</li>
<li>how to display selected radio button value in lwc</li>
</ul>
</div>
<div style="width: 50%; float:left; display:inline-block">
<ul style="list-style-type: square; font-size: 16px; margin: 0 0 0 54px; padding: 0;">
<li>display account related contacts based on account name in lwc</li>
<li>how to insert a record of account Using apex class in LWC</li>
<li>how to get picklist values dynamically in lwc</li>
<li>how to edit/save row dynamically in lightning component</li>
<li>update parent field from child using apex trigger</li>
</ul>
</div>
<div style="clear:both;"></div>
<br/>
<div class="youtubeIcon">
<img src="https://www.w3web.net/wp-content/uploads/2021/11/youtubeIcon.png" width="25" height="25" style="vertical-align:top; margin-right:10px;"/> <strong>TechW3web:-</strong> To know more, Use this <span style="color: #ff8000; font-weight: bold;">Link</span>
</div>
</div>
</div>
<!--End RelatedTopics Section-->
</div>
</lightning-card>
</template>
Example of changing and saving non-picklist value in datatable:
Changing and saving non-picklist value
Example of changing and saving a picklist value:
Changing and saving picklist value (1)
Last bit of console output:
Changing and saving picklsit value (2)
As this is my first time working with Lightning Web components, I would greatly appreciate any assistance you may provide. Thanks in advance.
I was able to get this custom data table component working for something I am developing to effectively bind records as rows. Here 2 differences I notice:
I did not include onvalueselect and oncellchange methods for the component html declaration, only the onpicklistchanged.
You may want to use your custom server side controller method instead of the built-in uiRecordApi->updateRecord one. Something tells me this may not play nice with row data from the data table. In my implementation, I was simply able to pass the draftValues over to the server side method which has a single parameter of list of sObject:
async saveRecords(event){
const updatedFields = event.detail.draftValues;
this.draftValues = [];
this.showSpinner = true
try{
await saveRelatedRecords({sObjs: updatedFields}) // server side save
.then((result) => {
this.updateMessage = result;
})
this.showSpinner = false;
if(this.updateMessage == 'success'){
this.showToast('Success', 'Record(s) Updated', 'success');
} else{
this.showToast('Error', this.updateMessage, 'error');
}
await refreshApex(this._wiredRecordData);
this.unsavedData = this.records;
} catch (error) {
this.showSpinner = false;
this.showToast('Error while updating or refreshing records', error.body.message, 'error');
}
}
In regards to your data not refreshing, I suggest you wire your getPayments method so that you can always get a fresh set from the server side, rather than trying to keep track of and maintain data changes on the client side, something like:
_wiredRecordData;
#wire(getRelatedRecords)
relatedRecords(getRecsResult){
const { data, error } = getRecsResult;
this._wiredRecordData = getRecsResult;
if(data){
this.records = data;
}
}
Then after your success toast in your save method, you can use
await refreshApex(_wiredRecords); and lwc knows to rerender based on the wiring (or at least I think that's how it works.)
Lastly, here is the server side controller method I have to dynamically generate column header information so it does not need to be hard coded into the component. However I did need to modify the custom component a bit to include a new "fieldapi" attribute so that the client side method knows what field to set for the changed value during the onpicklistchanged action.
#AuraEnabled(cacheable=true)
public static String getColumnHeaders(String sObjAPI, String fieldAPIs)
{
List<ColumnHeaderInfo> colHeaders = new List<ColumnHeaderInfo>();
Schema.DescribeSObjectResult sObjDesc = Schema.getGlobalDescribe().get(sObjAPI).getDescribe();
Boolean objIsUpdateable = sObjDesc.isUpdateable();
Map<String, Schema.SObjectField> objFields = sObjDesc.fields.getMap();
for(String field: fieldAPIs.split(','))
{
if(!objFields.keySet().contains(field.toLowerCase())){
continue;
}
Schema.DescribeFieldResult fieldDesc = objFields.get(field).getDescribe();
if(!fieldDesc.isAccessible()){
continue;
}
ColumnHeaderInfo colHeader = new ColumnHeaderInfo();
colHeader.label = fieldDesc.getLabel();
colHeader.fieldName = fieldDesc.getName();
colHeader.editable = fieldDesc.isUpdateable() && sObjDesc.isUpdateable();
colHeader.type_x = fieldDesc.getType().name().toLowerCase();
if(colHeader.type_x == 'picklist')
{
colHeader.type_x = 'picklist';
List<Schema.PicklistEntry> picklistValues = fieldDesc.getPicklistValues();
colHeader.typeAttributes = new TypeAttributes();
colHeader.typeAttributes.options = new List<Option>();
for(Schema.PicklistEntry ple: picklistValues)
{
Option opt = new Option();
opt.value = ple.getValue();
opt.label = ple.getLabel();
colHeader.typeAttributes.options.add(opt);
}
colHeader.typeAttributes.context = new FieldName();
colHeader.typeAttributes.context.fieldName = 'Id';
colHeader.typeAttributes.value = new FieldName();
colHeader.typeAttributes.value.fieldName = fieldDesc.getName();
colHeader.typeAttributes.fieldapi = fieldDesc.getName();
}
// multi-select picklist fields not supported so make them read-only
if(colHeader.type_x == 'multipicklist'){
colHeader.editable = false;
}
colHeaders.add(colHeader);
}
return JSON.serialize(colHeaders).replaceAll('type_x', 'type');
}
private class ColumnHeaderInfo
{
public String label;
public String fieldName;
public String type_x;
public Boolean editable;
public TypeAttributes typeAttributes;
}
private class TypeAttributes
{
public String placeholder;
public List<Option> options;
public FieldName value;
public FieldName context;
public FieldName label;
public FieldName tooltip;
public String fieldapi;
public String target;
}
private class Option
{
public String label;
public String value;
}
private class FieldName
{
public String fieldName;
}
I have a form that is built with Vuejs in my Rails 5.1 app. All my fields work well and persist data to the database, except for file uploads. I get the error
[Vue warn]: Error compiling template: printed at the top of the console, then essentially my entire template code, then
- <input v-model="variation.photo_one" type="file">:
File inputs are read only. Use a v-on:change listener instead.
I am new to Vuejs and cannot figure out how to get this to work even after reading many other online posts regarding this.
_form.html.erb
<%= content_tag :div,
id: "product-form",
data: {
id: product.id,
product: product.to_json(except: [:id, :created_at, :updated_at]),
variations_attributes: product.variations.to_json(except: [:product_id, :created_at, :updated_at]),
} do %>
...
<div class="col-md-4 upload-block">
<label>Photo One</label>
<input type="file" v-model="variation.photo_one" style="margin-bottom: .5em">
</div>
...
<% end %>
app_vue.js
import Vue from 'vue/dist/vue.esm'
import TurbolinksAdapter from 'vue-turbolinks'
import VueResource from 'vue-resource'
Vue.use(VueResource)
Vue.use(TurbolinksAdapter)
document.addEventListener('turbolinks:load', () => {
Vue.http.headers.common['X-CSRF-Token'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content')
var element = document.getElementById("product-form")
if (element != null) {
var id = element.dataset.id
var product = JSON.parse(element.dataset.product)
var variations_attributes = JSON.parse(element.dataset.variationsAttributes)
variations_attributes.forEach(function(variation) { variation._destroy = null })
product.variations_attributes = variations_attributes
var app = new Vue({
el: element,
data: function() {
return { id: id, product: product }
},
methods: {
addVariation: function() {
this.product.variations_attributes.push({
id: null,
name: "",
photo_one: "",
//position: "",
_destroy: null
})
},
removeVariation: function(index) {
var variation = this.product.variations_attributes[index]
if (variation.id == null) {
this.product.variations_attributes.splice(index, 1)
} else {
this.product.variations_attributes[index]._destroy = "1"
}
},
undoRemove: function(index) {
this.product.variations_attributes[index]._destroy = null
},
saveProduct: function() {
// Create a new product
if (this.id == null) {
this.$http.post('/products', { product: this.product }).then(response => {
Turbolinks.visit(`/products/${response.body.id}`)
}, response => {
console.log(response)
})
// Edit an existing product
} else {
this.$http.put(`/products/${this.id}`, { product: this.product }).then(response => {
Turbolinks.visit(`/products/${response.body.id}`)
}, response => {
console.log(response)
})
}
},
existingProduct: function() {
return this.product.id != null
}
}
})
}
})
Files are a bit awkward in Vue. As the message says, you cannot use v-model for an input with type="file". Instead you must use the change event and call a method in your component to manually handle the file.
<input type="file" #change="handleFileChange" />
methods: {
handleFileChange(event) {
//you can access the file in using event.target.files[0]
this.fileField = event.target.files[0];
}
}
When you submit the AJAX request, you will likely need to submit a FormData object instead of submitting a javascript object. The MDN docs have an explanation on how to use that. I find the FormData is the more awkward part of dealing with file uploads. https://developer.mozilla.org/en-US/docs/Web/API/FormData
Here i am trying to display html content stored in database.When i try it to display in js it gives me "Uncaught ReferenceError: VAR_1 is not defined" in console.
Database:
<div id="dashboard-greeting" class="museo">
<div class="dashboard-greeting-instructions">
<span>Track Progress</span>
<div class="dashboard-greeting-counter round">
<div class="dashboard-counter-label">Courses Completed</div>
<div class="dashboard-counter-value">VAR_1</div>
</div>
<div class="dashboard-greeting-counter round">
<div class="dashboard-counter-label">Courses Needed</div>
<div id="subNeeded" class="dashboard-counter-value"></div>
<script>
var subNeedVar = VAR_2 - VAR_1;
$("#subNeeded").html(subNeedVar);
</script>
</div>
</div>
</div>
.js
<div class="tool-button-container">
<input type="submit" name="View" value="LookUp" id="campaignSubmit" class="buOrange large" onClick="validateConfigValues('configKeyName');"/> </div>
function validateConfigValues(id1){
$.ajax({
type: 'POST',
url: '<%=request.getContextPath()%>/adminConfigTest',
data: ({configKeyName:configKeyName, clientId :clientId ,batchId : batchId, languageId : languageId}),
cache: false,
success: function(data) {
var deleteCachingBtn = $('<br><div id="deleteBtn"><Button id="deleteCaching" name="deleteCaching" class="buOrange large" onClick=deleteFromCaching(\'' + configKeyName + '\')> Remove from Cache </div>');
var displayStringAppData = "";
var obj = JSON.parse(data);
$.each(obj, function(index,value) {
displayStringAppData = displayStringAppData+"<br>"+value+"<br>";
alert("displayStringAppData"+displayStringAppData);
});
$("#dbModelWindow").html(displayStringAppData);
if(~data.indexOf("Config is not found in DB also.")) {
} else {
$("#dbModelWindow").append(deleteCachingBtn);
}
$('#dbModelWindow').modal({
"escClose": true,
"overlayClose": true,
"onShow": function() { $.modal.setContainerDimensions();},
});
},
error: function(xhr, textStatus, error){
alert("Error occured. Please try after some time.");
}
});
}
}
.java
#RequestMapping(value="/adminConfigTest", method= RequestMethod.POST)
#PreAuthorize("hasPermission(#adminConfigTest,'ADMIN_TEXT_CONFIG')")
#ResponseBody
public String getAdminConfigTestPost(HttpServletRequest request) throws Exception {
String configKeyName = request.getParameter("configKeyName");
String clientId = request.getParameter("clientId");
String batchId = request.getParameter("batchId");
String language = request.getParameter("languageId");
List<String> arrList = new ArrayList<String>();
try{
Number languageId = null;
if(StringUtils.isBlank(language)){
languageId = RCConstants.ENGLISH_LANGUAGE_ID;
} else {
languageId = Long.parseLong(language);
}
if(StringUtils.isBlank(clientId)){
configManager.getConfigValue(configKeyName, null, "", false, true, languageId, arrList);
}
if(!StringUtils.isBlank(clientId) && StringUtils.isBlank(batchId)){
configManager.getConfigValue(configKeyName, Long.parseLong(clientId), "", false, true, languageId, arrList);
}
if(!StringUtils.isBlank(batchId)){
configManager.getConfigValue(configKeyName, Long.parseLong(batchId), languageId, arrList);
}
} catch (Exception e) {
logger.error(e ,e);
throw e;
}
return JSONSerializer.toJSON(arrList).toString();
}
public String getConfigValue(String configKey, Number batchId, Number languageId, List<String> arrList)throws Exception{
if(arrList != null){
arrList.add("Get config value for : "+ configKey);
arrList.add("batch Id : "+ batchId);
arrList.add("Language : "+ StringUtils.getLanguageCode(languageId));
}
try{
String configKeyValue = null;
String localConfigKeyWithBatchId = batchId+"-"+configKey+"-"+StringUtils.getLanguageCode(languageId);
String queryString = "from Config as model where model.configKeyName = ? and model.batchMetaDataId = ? and model.languageId = ? and model.isDeleted = 0" ;
List<Config> configList = getHibernateTemplate().find(queryString, configKey , batchId ,languageId);
if(!configList.isEmpty()) {
for (Config config : configList) {
configKeyValue = config.getConfigKeyValue();
}
CacheUtil.put(RCConstants.LOCAL_CACHE_WITH_BATCH,localConfigKeyWithBatchId, configKeyValue);
logger.debug("Returning value from db : "+configKey+" - "+configKeyValue);
if(arrList != null){
arrList.add("Db: returning batch and language specific value : " + configKeyValue );
}
}
return configKeyValue;
} catch (RuntimeException re) {
log.error(re, re);
throw re;
}
}
CacheUtil.java
public static Cache localEhCache = null;
public static Cache localEhCacheWithBatchId = null;
public static void put(int cacheNumber, Object key, Object value) {
if (cacheNumber == RCConstants.LOCAL_CACHE) {
localEhCache.put(new Element(key, value));
} else if (cacheNumber == RCConstants.LOCAL_CACHE_WITH_BATCH) {
localEhCacheWithBatchId.put(new Element(key, value));
}
}
But if i rewrite VAR_1 again by erasing VAR_1. It wont show this error.
I googled about this topic but didn't find any solution.
Please help me or suggest me what is going wrong here.
Im using https://github.com/danialfarid/ng-file-upload plugin to manage my file upload, following is my code.
HTML
<form name="form">
Single Image with validations
<div class="button" ngf-select ng-model="file" name="file" ngf-pattern="'image/*'"
ngf-accept="'image/*'" ngf-max-size="20MB" ngf-min-height="100"
ngf-resize="{width: 100, height: 100}">Select</div>
Multiple files
<div class="button" ngf-select ng-model="files" ngf-multiple="true">Select</div>
Drop files: <div ngf-drop ng-model="files" class="drop-box">Drop</div>
<button type="submit" ng-click="upload()">submit</button>
</form>
Controller
// upload on file select or drop
$scope.upload = function (file) {
file = new FormData();
file = {'file': file};
imageFind.search(file, $scope.documentsOffsetStart, $scope.titleSorting)
.then(
function (response) {
console.log('Success ' + response.config.data.file.name + 'uploaded. Response: ' + response.data);
},
function (response) {
console.log('Error status: ' + response.status);
}, function (evt) {
console.log('progress: ' + progressPercentage + '% ' + evt.config.data.file.name);
});
};
Image find service
]).factory('imageFind', [
'imageService', 'ApiService',
function (imageService, ApiService) {
return {
search: function (file, start, sort) {
var formData, params={};
if (start == null) {
start = 0;
}
if (sort == null) {
sort = "";
}
var data = {
start: start,
sort: sort
};
data = $.param(data);
var config = {'Content-Type': undefined};
return ApiService.post(imageFindPint, data, config);
}
};
}
]);
Im getting following error when image upload:
Error: 'append' called on an object that does not implement interface FormData.
jQuery.param/add
do you see I'm doing anything wrong?
Pass <button type="submit" ng-click="upload('file')">submit</button>
This should solve the issue.
In the controller
// file = new FormData();
// file = {'file': file};
can be removed but need to add FormData() to services.
I have a page in MVC, where i need to display the details of the records.
The records needed to be fetched from 2 tables for which i have Model separately.
Now, for this page needing both the models, I have created another model which have those 2 model referred.
[Please note, following nomenclature's are only for example purposes.]
public class CombinedModel
{
public Model1 objModel1 { get; set; }
public Model2 objModel2 { get; set; }
}
In the view [Details.cshtml], I have following code:
#model Application.Web.Models.CombinedModel
<div>
#Html.Label("Label text: ", htmlAttributes: new { #class = "control-label" })
#Html.DisplayFor(model => model.objModel1.Property1, new { htmlAttributes = new { #class = "form-control" } })
</div>
And a popup code
<div id="Modal">
<div>
#Html.Label("Popup label text:", htmlAttributes: new { #class = "control-label" })
#Html.DisplayFor(vmodel => vmodel.objModel2.Property2, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
The page loads with the data in from the first model successfully from controller action.
I needed Data in the popup code, only when user clicks on particular record, from where View will send ID and will display record for that particular ID from the second model.
In Controller:
public class ControllerNameController : Controller
{
[HttpGet]
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
[ValidateInput(false)]
public ActionResult Details(int? Id, string strType, string strVersionID)
{
var Details1 = db.Table1.FirstOrDefault(rd => rd.SomeID == Id);
CombinedModel modelCombined = new CombinedModel();
Model1 objectM1 = new Model1();
objectM1.Property1 = Details1.Column1;
var VersionDetails = db.Table2.FirstOrDefault(rvd => rvd.somePrimaryKeyID == Convert.ToInt32(strVersionID));
if (VersionDetails != null)
{
Model2 objectM2 = new Model2();
objectM2.vCreatedOn = VersionDetails.Property2;
modelCombined.objModel2 = objectM2;
ViewBag.VersionID = VersionDetails.VersionID;
}
modelCombined.objModel1 = objectM1;
return View(rmodel);
}
}
The page landing URL is:
function JavascriptFunctionInParentView(IDToPass, strTypeToPass)
{
top.location.href = "#Url.Action("Details", "ControllerName")"
+ "?Id=" + IDToPass
+ "&strType='" + strTypeToPass + "'"
+ "&strVersionID='0'";
}
SO, when first time page loads, we have strVersionID as Zero. So, it will not enter in VersionDetails block and fill only Model1 data.
Now, when we are Details page, there is a grid, from which, I need to populate the version details in the popup, for which I have working code as following:
function recordDoubleClickRuleVersion(args) {
top.location.href = "#Url.Action("Details", "ControllerName")"
+ "?Id=" + #Url.RequestContext.HttpContext.Request.QueryString["Id"]
+ "&strType=" + '#Url.RequestContext.HttpContext.Request.QueryString["strType"]'
+ "&strVersionID=" + args.data.VersionID;
}
// ....
$(function () {
if ('#(ViewBag.VersionID)' == "") {
$("#Modal").ejDialog("close");
}
if ('#(ViewBag.VersionID)' != "") {
$("#Modal").ejDialog(
{ enableModal: true, enableResize: false, close: "onDialogClose", width: "60%" });
$("#Modal").ejDialog("open");
}
})
My problem is, when i call this Version details popup, page postbacks and then data comes.. I know i have given #Url.Action to it so it is behaving like this way.
I needed it to be by complete Client-side code and I tried following code as well. It open's popup but doesn't fill value in it.
$.ajax({
type: "GET",
data: ({
"Id": #Url.RequestContext.HttpContext.Request.QueryString["Id"],
"strType": '#Url.RequestContext.HttpContext.Request.QueryString["strType"]',
"strVersionID": args.data.VersionID }),
url: '#Url.Action("RuleDetails", "Rules")',
})
.done(function (RuleVersionDetails) {
// 1. Set popup
$("#Modal").ejDialog(
{ enableModal: true, enableResize: false, close: "onDialogClose", width: "60%" });
// 2. Open popup
$("#Modal").ejDialog("open");
});
Can you please tell me the solution for this ?
You can change you Details() Action to return a Json object, and then fill the dialog with it.
$.ajax({
type: "GET",
data: ({
"Id": #Url.RequestContext.HttpContext.Request.QueryString["Id"],
"strType": '#Url.RequestContext.HttpContext.Request.QueryString["strType"]',
"strVersionID": args.data.VersionID }),
url: '#Url.Action("RuleDetails", "Rules")',
})
.done(function (jsonData) {
// **TODO: file dialog with properties of jsonData**
// 1. Set popup
$("#Modal").ejDialog(
{ enableModal: true, enableResize: false, close: "onDialogClose", width: "60%" });
// 2. Open popup
$("#Modal").ejDialog("open");
});
The best approach for your case is using bootstrap modal.Go here and check its documentation and how to config. If you aren't familiar with bootstrap or modal, it really worth to learn.
But remember when you want sent data to modal section, make it dynamic based on your item id in grid.