ExtJS 6 - How to upload a file without using form? - extjs

Ext JS provides fileuploadfield which is bundled with a button to browse local files. I just need to upload a file using as soon as it is selected from local instead of using a submit button in order to trigger the post process. Could not find an event which is fired after the file is selected.
p.s. Actually, the version I use is Ext JS 6 but I think the solutions based on previous versions do the work as well.

Form is not required. You can use AJAX and FormData.
var file = s.fileInputEl.dom.files[0],
data = new FormData();
data.append('file', file);
Ext.Ajax.request({
url: '/upload/files',
rawData: data,
headers: {'Content-Type':null}, //to use content type of FormData
success: function(response){ }
});
Online demo here

You will need to use a form if you want to submit the file. Even if you want the button to be in a toolbar, you can enclose it in a form and it will still look like a normal toolbar button (you will need to specify the proper ui config for this).
Example:
dockedItems: [{
dock: 'top',
xtype: 'toolbar',
items: [{
xtype: 'form',
padding: '10 0 0',
url: 'submit/image',
items: {
xtype: 'filefield',
buttonOnly: true,
width: 100,
buttonConfig: {
text: 'Add logo',
width: '100%',
ui: 'default-toolbar-small'
},
listeners: {
change: function (filefield) {
filefield.up('form').submit();
}
}
}
}, {
text: 'Remove logo'
}, '-', {
text: 'Discard changes'
}]
}]
Working fiddle example: https://fiddle.sencha.com/#view/editor&fiddle/1pdk

While I agree with scebotari's answer that in your case embedding a form in the toolbar is probably the easiest solution, for the sake of answering the original question:
If you really cannot or do not want to use a form and you're not limited regarding browser support, have a look at the FileReader.
The idea is to read the file contents on the client side (JavaScript) and then send the data using a regular AJAX request.
Your code could look like that:
function (fileField) {
var file = fileField.fileInputEl.dom.files[0],
reader;
if (file === undefined || !(file instanceof File)) {
return;
}
reader = new FileReader();
reader.onloadend = function (event) {
var binaryString = '',
bytes = new Uint8Array(event.target.result),
length = bytes.byteLength,
i,
base64String;
// convert to binary string
for (i = 0; i < length; i++) {
binaryString += String.fromCharCode(bytes[i]);
}
// convert to base64
base64String = btoa(binaryString);
Ext.Ajax.request({
url: 'save-file.php',
method: 'POST',
params: {
data: base64String
}
});
};
reader.readAsArrayBuffer(file);
}

You are looking for the event change on the fileuploadfield.
The code could look like this:
Ext.create('Ext.form.Panel', {
renderTo: Ext.getBody(),
title: 'Upload Panel',
items: [{
xtype: 'filefield',
name: 'photo',
fieldLabel: 'Photo',
labelWidth: 50,
msgTarget: 'side',
allowBlank: false,
anchor: '100%',
buttonText: 'Select Photo...',
listeners: {
change: function (me, value, eOpts) {
console.log('trigger upload of file:', value);
}
}
}],
});
Fiddle https://fiddle.sencha.com/#view/editor&fiddle/1pd2

Related

extjs store.load after form.submit

I'm trying to reload an Extjs-store, after user has download a PDF.
The process is the following:
User double clicks a cell in GridPanel
Form is created, submitted, and a procedure in the backend creates an PDF and makes some changes on data of GridPanel store
PDF will be downloaded by user
But how to reload the store with the new data in it?
There is no afterRender on form-submit.
I think this should be an easy problem, but I do not have any ideas how to solve it.
This is a snipped I found in my code base (inside a controller):
var form = button.up().up().down('form').getForm();
form.submit({ success : this.onFileUpload, failure: this.onFileUpload, scope: this});
...
onFileUpload: function (form, action){
var data = action.result.data;
...
if (action.result.success){
...
//**your store reload could be here!**
...
} else {
...
}
}
My form response is not responding with a file (just some standard html return), but I guess it should work.
here is a bit of my code:
function makeprintForm(array, setStatusX, grid) {
var filename = 'asd.pdf';
var url_pdf = 'someURL?FileName=' + filename;
var printForm = Ext.create('Ext.form.Panel', ({
url: currentContextPath + encodeURIComponent('http://' + host + ':' + port + url_pdf),
hidden: true,
id: 'printForm',
name: 'printForm',
method: 'post',
standardSubmit: true,
target: '_blank',
items: [{
xtype: 'textfield',
fieldLabel: 'print_id',
name: 'print_id',
value: array
},
{
xtype: 'textfield',
fieldLabel: 'username',
name: 'username',
value: username
},
{
xtype: 'textfield',
fieldLabel: 'language_field',
name: 'language',
value: language
}
]
}));
Ext.getCmp('printForm').getForm().submit({ success : this.reload_grid_after_submit(), scope: document.getElementById(nameSpace + 'formIS')});
}
function reload_grid_after_submit(){
console.log('reload_grid_after_submit');
Ext.getCmp('grid').getStore().proxy.setExtraParam('status', 'NEW');
Ext.getCmp('grid').getStore().load();
}
You can use a form in an alert box. I used a window here. Then onsubmit of the form you can use findRecord to find a record from the store and edit it. For better explanation please find the fiddle here. P.S sorry for the delay I was on a vacation. Please mark it as an answer if it's correct so it helps other people in the future. Or please comment if there is something which needs to be changed. Thanks
Ext.getCmp('myGrid').addListener('rowdblclick', function (a, b, c, d) {
win = new Ext.Window({
width: 300,
height: 150,
draggable: false,
border: false,
modal: true,
resizable: false,
items: [{
xtype: 'textfield',
fieldLabel: 'What is your new name',
id: 'newNameField'
}, {
xtype: 'button',
name: 'sampleButton',
text: 'Change My Name!',
style: 'margin:15px',
width: 150,
handler: function () {
name = Ext.getCmp('myGrid').getStore().getAt(d).data['name'];
console.log(name);
var newName = Ext.getCmp("newNameField").value;
console.log("replacing " + name + " with " + newName + " in the store");
var entry = userStore.findRecord('name', name);
entry.set('name', newName);
win.hide();
}
}]
})
win.show();
})

Read text file into the text area in extjs

I have mail.txt on my local machine and i want to display it on the UI using extjs. I created a textarea and want to import mail.txt into it.
Ext.define('com.company.view.dashboard.Dashboard', {
extend: 'Ext.panel.Panel',
alias: 'widget.dashboard',
layout: 'fit',
iconCls: 'dashboard-tree',
initComponent: function(config) {
Ext.apply(this, {
items: [
{
xtype: 'fieldcontainer',
fieldLabel: 'P&L',
labelWidth: 100,
layout: 'hbox',
items: [{
xtype: 'textarea',
flex: 1
}]
}
]
});
this.callParent(arguments);
}});
Here If you want to Display text file in UI then what I will suggest you is put you text content in to JSON format and then on top of window or Panel you can display that.
In This example I am displaying on window. You can make as per your requirment.
Here is MyMessage function which can take the response and then display on MyMessageWindow .
MyMessage : function(){
var me = this;
Ext.Ajax.request({
url : URL of your JSON
method : 'GET',
dataType:'json',
scope : me,
headers : {
"Accept" : "application/json; charset=utf-8"
},
success : function (response, args) {
var data = Ext.decode(response.responseText);
var Msgtext = data.R.MSG; // This is depend on how you binding data in JSON.
me.MyMessageWindow(Msgtext);
}
});
},
MyMessageWindow : function(Msgtext){
var FailedMsgShow = function (text) {
Ext.create({
xtype: 'window',
title: 'P&L',
width: 600,
height: 450,
html:text,
scrollable: true,
}).show();
};
FailedMsgShow('<text style="color:green;">'+Msgtext+'</text>');
},
Note : You can display on any component like panel. I just suggesting you to put on window. you can make on panel as well instead of fieldContainer.

posting form to iframe with extjs without rendering to bidy

I am trying to post a form to an iframe. my issue is that my form gets posted just fine when I render the iframe to body. But the issue with this is that the container displays at the bottom of the page instead of the place where I want it to show. If I don't use the renderTo property, my form never gets posted to iframe at all. It almost seems like that in the case when I do not use renderTo property, i think my form does not even see the iframe.
here is my code thats working for the form post but the container falls all the way to the bottom of the page
var myContainer = Ext.create('Ext.form.FieldSet', {
title: "my frame container",
labelWidth: 1,
bodyStyle: "padding-right:15px;padding-left:25px;",
renderTo: Ext.getBody(),
items: [
{
xtype: 'box',
autoEl: {
tag: 'iframe',
name: 'myIframe',
id: 'myIframe'
}
}
]
});
$('myform').submit();
This gets the form submitted but the panel drops down to the bottom of page. How can I keep its location and also be able to post to it.
Again if I take this part out renderTo: Ext.getBody() then the form never gets posted to iframe.
I wonder if there is a way to render to a specific div may be? Not sure if that would work as well.
EDITED
I tried doing this
renderTo: 'x-panel'
ext-all.js Uncaught TypeError: Cannot read property 'dom' of null
** Complete Code with form Submission **
var f = document.createElement("form");
f.setAttribute('method',"post");
f.setAttribute('name',"checkout-form");
f.setAttribute('id',"checkout-form");
f.setAttribute('target',"myIframe");
f.setAttribute('action',"http://example.com");
var formFields = [
'field1',
'field2',
field3'
];
for (var i = 0; i < formFields.length; i++){
var formFieldName = 'formFieldName'+i;
formFieldName = document.createElement("input");
formFieldName.type = "text";
formFieldName.name = formFields[i];
f.appendChild(formFieldName);
}
var myContainer = Ext.create('Ext.form.FieldSet', {
title: "my title",
labelWidth: 1,
bodyStyle: "padding-right:15px;padding-left:25px;",
//renderTo: Ext.getBody(),
renderTo: Ext.getElementById("myId"),
items: [
{
xtype: 'box',
autoEl: {
tag: 'iframe',
name: 'myIframe',
id: 'myIframe',
},
listeners: {
load: {
element: 'el',
fn: function () {
console.log("iframe loaded");
$('iframe#component-9808').css('border','0');
}
}
}
}
]
});
$("body").append(f);
$('#checkout-form').submit();
Maybe you can try to send your form data like this:
Ext.create(Ext.form.Panel).submit({
clientValidation: false,
method: 'GET',
params: {
// Your params like:
id: myId
},
standardSubmit: true,
target: '_blank',
url: 'your/url'
});
var formFields = [
'field1',
'field2',
field3'
];
You have one ' missing there also... Wacthout!

Remove fake path in extjs

I am new to the extjs.Please help me to remove fakepath issue in filefield.I do not want to get the exact path .Removing "fakepath" string is ok for me. Code runs perfectly but path displays as C:\fakepath....
I created a seperate window inorder to upload a file. In my case Application should have a seperate window as a result of selecting a option from the menu.
Here is crateWindow function of my code :
createWindow: function() {
var desktop = teamApp.getDesktop();
var win = desktop.getWindow(this.windowId + '_win');
if(!win) {
win = desktop.createWindow({
id: this.windowId + '_win',
title: 'Upload a Audio',
iconCls: 'icon-upload-picture',
height:150,
width: 500,
layout: 'fit',
renderTo: Ext.getBody(),
items:
{
xtype: 'panel',
frame:true,
bodyPadding: '10',
items: [{
xtype: 'filefield',
id: 'form-file',
labelWidth: 100,
//emptyText: 'Select an audio file',
fieldLabel: 'Audio File',
name: 'file-path',
fieldWidth: 250,
allowBlank: false,
anchor: '100%',
buttonText: 'Browse'
}],
buttons: [{
text: 'Save',
handler: function(){
var form = this.up('form').getForm();
if(form.isValid()){
form.submit({
//url: 'file-upload.php',
waitMsg: 'Uploading your Audio file...',
success: function(fp, o) {
msg('Success', 'Processed file "' + o.result.file + '" on the server');
}
});
}
}
}]
}
})
}
win.show();
return win;
}
As far as I understand you cannot, as per documentation at http://docs.sencha.com/extjs/4.1.3/#!/api/Ext.form.field.File
Because there is no secure cross-browser way to programmatically set the value of a file input, the standard Field setValue method is not implemented. The getValue method will return a value that is browser-dependent; some have just the file name, some have a full path, some use a fake path.
Update
What you can do is set fieldWidth to zero and add another textfield before the filefield. You can set the value of this textfield as the name of file selected by user by listening to change of file field and parsing the value from last index of \ till last.

Ext JS 4.1 - User-defined validation doesn't bind button

I defined a validation which controls if the id is unique or not to bind a button. It works well with built-in validations well, but it doesn't bind for my own validation.
Here's what I've tried:
View - FormPanel:
Ext.define(appName + '.view.user.UserForm', {
extend: 'Ext.form.Panel',
requires: [appName + '.view.language.LanguageCombo'],
alias: 'widget.userform',
// title : 'User Form',
iconCls: 'icon-form',
frame: true,
padding: '5 5 0 5',
border: true,
buttonAlign: 'right',
width: '100%',
// height : 200,
monitorValid: true,
bodyPadding: 10,
fieldDefaults: {
labelAlign: 'left',
labelWidth: 110,
anchor: '98%',
allowBlank: false,
selectOnFocus: true,
msgTarget: 'side'
},
initComponent: function () {
var me = this;
this.title = bundle.getMsg('userform.title');
this.items = [{
xtype: 'numberfield',
minValue: 1,
fieldLabel: bundle.getMsg('userform.field.recordId'),
name: 'recordId',
itemId: 'recordId'
}, {
];
this.btnReset = Ext.create('Ext.ux.button.ResetButton', {
handler: function (btn) {
me.getForm().reset();
}
});
this.btnSubmit = Ext.create('Ext.ux.button.SaveButton', {
disabled: true,
formBind: true
});
this.buttons = [me.btnReset, me.btnSubmit];
this.callParent(arguments);
}
});
Controller Method:
var form = this.getUserForm();
if (field.getValue() && field.getValue() != '') {
Ext.Ajax.request({
url: 'user/chkRecordIdUnique.ajax',
method: 'POST',
params: {
recordId: field.getValue()
},
success: function (response, options) {
var res = Ext.decode(response.responseText);
if (!res.success) {
field.markInvalid(bundle.getMsg('record.taken'));
form.getForm().markInvalid(bundle.getMsg('record.taken'));
}
}
});
}
According to the docs, markInvalid doesn't actually change the validity of a field. It just applies the visual styles as if the field had an error. And there's no isValid property to set. All validity is determined by an immediate call to the isValid method.
As it stands, Ext JS forms do not support asynchronous validation natively. It assumes that either all validation is done on the client side, or that the server will perform validation. If you want to perform an Ajax call to determine if the form is valid before enabling the save button, I would recommend making your own validate method with a success callback. Manually enable the save button if the Ajax call succeeds and the rest of the form is valid. Then on form change, you can disable the save button again.
Side note: width should be a number, not a percentage.

Resources