I have file upload control using which i uploading image file on server. In this operation I am going submitting form two times. Issue is that after submitting form first time file upload filed giving value null at second submit.
lets see my code as below.
this.userPhoto = new Ext.create('Ext.form.field.File', {
xtype: 'filefield',
padding: '5 5 5',
cls: 'p-photo-upload',
emptyText: 'Photo',
buttonOnly: true,
fieldLabel: fleet.Language.get('_FLEET_USER_USERDETAIL_PHOTO_'),
name: 'photo',
labelWidth: 200,
width: '26%',
msgTarget: 'under',
listeners: {
scope: this,
change: function (t, value) {
var data = {};
data.userPhoto = t.value;
data.imageType = 'userPhoto';
var postdata = Ext.encode(data);
postdata = Base64.encode(postdata);
this.UserDetailform.getForm().submit({
scope: this,
url: FLEET_PROXY_URL + 'index.php?c=user&a=uploadphoto',
params: { postData: postdata },
success: function (form, action) {
this.setLoading(false);
var b = Ext.decode(action.response.responseText);
console.log(b);
if (b && b.data && b.success === "S") {
var img = '<img src="' + FLEET_SERVER_URL + 'images/temporary/' + b.data.photoname + '" />';
this.userimage.setValue(img);
} else {
this.UserDetailform.getForm().findField('photo').markInvalid(fleet.Language.get(b.errors[0].photo));
}
}
});
}
}
});
this.userPhoto is the object of Ext.form.field.File, after the browse file I am uploading it by submitting form (you can see code in listeners change event of this.userPhoto) this form submit method I used for save temporary file at server side. Next I am going to save same file and other user details on second submit, but on second submit I got nothing from This.userPhoto.
Please see below screen shot you can get better idea about this.
in image you can see there is BROWSE and SAVE button
first form submit method done on after select the file and second on SAVE button click.
The sencha file upload field cannot retain its state because the underlying HTML field is a file upload field which is not intended to keep its state across form submission.
There are so many drawbacks when using file upload fields in your forms, that I have switched to a different approach for image upload.
In my app, where image uploads are required, the file upload field is not connected to the actual form, but submitted on its own, and the backend then returns a data URL of the image to the client. The client then usually puts this data URL into a hiddenfield in the form. An xtype:'image', bound to the hidden field, displays the content of the hidden field (= the image) in the frontend.
That way,
the data URL can be more easily handled in a database because it is a "readable" string, not a blob,
the data URL is loaded and saved together with all the other data in the form,
the data URL can be loaded and saved infinitely often,
I only need one backend endpoint that handles image uploads, and can work with data URLs (strings) from there on,
all forms can be submitted as JSON (a file upload field enforces standard submission, so when a file upload field is added to an existing form, I would have to throw away all backend code I already have for that endpoint).
The main drawback is that the image goes over the wire more often than with a simple file upload, but at least for me, this is a minor issue.
Related
I am working on a form set for a client. In a nutshell:
The forms are filled out by my client’s customers by selecting different options on each form.
Each form can have multiple instances, depending on the customer.
At the end of the process, the customer can opt to either sign one or all the forms digitally or decline to sign them digitally and at the end of the process the forms are printed out and signed manually.
To accomplish this, I’ve created a signature plugin written in jQuery. Once the customer fills out the forms, they are presented each form separately. To sign the form digitally they simply tap (click) the signature block, a dialog with a canvas element appears, they sign the form and save it, the signature appears in the form, and they move on to the next form.
Here is the portion of the code that stores the completed signature and adds the image to the form:
$.sig = {
signatures: {},
}
function signatureSave() {
var canvas = document.getElementById("sigcanvas"),
dataURL = canvas.toDataURL("image/png");
document.getElementById($.sig.target).src = dataURL;
$.sig.signatures[$.sig.target].url = dataURL;
$.sig.signatures[$.sig.target].hasSignature = true;
};
The function is only called if the signature is saved, if there is no signature, the $.sig.signatures[$.sig.target].hasSignature remains false and the system skips the object.
This all works as intended, almost.
My problem lies in the process used to save the form information. If the customer does not sign any forms digitally the form information is simply saved and the forms are printed out, no need to save any signatures.
If the customer signs at least one form, though, the signatures must be sent to the server using the FormData() object.
I’ve used the FormData object in other projects for the client successfully, but only when the customer uploads one or more images to the browser using the input file element. It’s a pretty simple process because the resulting images have a img.file property that I send to the server.
Not so with a canvas object. All I get is the .src property, an any attempt to use anything from the resulting .png image that is created in the function above results in either a “cannot use a blob” or some other error.
Now I know if I have a single image, I can send it using AJAX with the following:
$.ajax({
type: "POST",
url: "script.php",
data: {
imgBase64: dataURL
}
})
Problem is that I am sending from one to x number of signatures.
Edit: I forgot to add this in. This is the function that is supposed to create the FormData object used to send the signatures to the server (and where my problem lies):
function getUploadData() {
var upl = new FormData();
$.each($.sig.signatures, function (e, u) {
if (u.hasSignature == true && u.url != null) {
var im = new Image();
im.src = u.url;
upl.append(u.target, im, u.target + '.png');
}
})
return upl;
}
I've tried all the tricks and nothing is working. The var im = new Image(); as well as the following line are just my latest ill fated attempt.
Picture perfect would be the ability to save the image information in the $.sig.signatures object so I can simply loop through any signatures that are signed, add them as elements of the FormData object, and then send the FormData object as the data for the AJAX call. As stated before, I use this method in other projects and works fine.
Does anyone know a way to do this?
Please note:
The server-side AJAX processor functions correctly.
The signature process works correctly (customer signs canvas, signature is displayed, signature information is stored).
All I need is how to send multiple images created using the canvas element in a FormData object to the server.
I know the answer is staring me right in the face, but I am just not getting it. Any hints or suggestions would be greatly appreciated!
Edit: Just a note. I've searched the entire afternoon for this and have found entries that either deal with sending multiple files using FormData and AJAX - but the files are uploaded to the browser (not created using Canvas), or single files sent to the server that are created using Canvas, but nothing about sending multiple files sent using FormData and AJAX that are created using Canvas. Oje!
As stated, the answer was staring me in the face, but I didn't see it because was looking behind the wrong door. FormData has nothing to do with it (Homer Dope Slap!).
Since I already have the data stored in $.sig.signature for each signature, I just need to send the information to the server as the data in the AJAX function. I updated my function above as shown:
function getUploadData() {
var upl = {};
$.each($.sig.signatures, function (e, u) {
if (u.hasSignature == true && u.url != null) {
upl[e] = u.url;
}
})
return upl;
}
Since the form information is sent as JSON I just add the signature info to the object that contains the form information, JSON.stringify it and send it on its way. This should work because the information retrieved above are strings.
Server side will look something like this:
$info = json_decode( $_POST['info'] );
// Various validation routines and checks
foreach( $info->signatures as $sig=>$data ):
$data = str_replace('data:image/png;base64,', '', $data);
$data = str_replace(' ', '+', $data);
$img = base64_decode($data);
// Do some processing, file naming, database saving and other general dodads
$success = file_put_contents( $file, $img );
endforeach;
The above function is still concept, I am reworking some of the code but this should work.
Credit is given to this post for opening my eyes:
post sending base64 image with ajaxpost sending base64 image with ajax
So question answered and yeah, I deserve a dope slap, but all comes out right in the end.
CAVEAT: Works like a charm.
I am using JavaScript to take the info from a form completed by the user, then sending this data to PHP and generate a PDF with FPDF. The problem is I want the browser to ask the user to save the PDF or view it online but
I cannot figure out how. The PDF generates correctly but only when I save it directly to a certain path specified by me.
The question is how do you guys send data from JavaScript to PHP to generate a PDF file then the browser asks the user to open or download, Or how can I make a function where the user can retrieve this PDF.
The JavaScript:
function senddata() {//this activates when i push a button not a submit
var peticion = new XMLHttpRequest();
peticion.open('POST', 'generatepdf.php');
var nueva2 = {};
var key;
for (i = 0; i < 6; i++) {
key = document.forms[0].elements[i].id;
nueva2[key] = document.forms[0].elements[i].value;
}//here i take my data from the form and make an object
var json = JSON.stringify(nueva2);//here i tranform my object to json string so i can send it to my php
var parametros = "json_string=" + json;//here I do this so later I can easily transform the $_POST to an array in the form json_decode($_POST["json_string"],true);
peticion.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
peticion.send(parametros);//it sends ok
}
The PHP with the FPDF class and things
<?php
require('fpdf/fpdf.php');
require('functions.php');
if($_SERVER['REQUEST_METHOD']=='POST'){
$datos=json_decode($_POST["json_string"],true); //here i have my data in an array format so i can use the parameters to fill my pdf fields
//...lots of pdf things here...//
$pdf->Output('F',"pdfs/Cotizacion ".$datos["nombres"]." ".$datos["apellidos"].".pdf");//this works but never ask the user
//$pdf->Output('D',"pdfs/Cotizacion ".$datos["nombres"]." ".$datos["apellidos"].".pdf");//this should force a dowload or send to the browser but doesnt work
//$pdf->Output();//this should send to the browser but doesnt work
}
To view your PDF inline to the browser, you should use the I variable instead. View full documentation here.
Also I don't think outputting the file in two methods at the same time works. It might conflict each other. The best way to do that is to test each method and if it does conflict each other just simply add a condition for the user to decide whether he/she wants to download or view it in the browser. Hope this helps.
Scenario :
I have aspx page which I need to Iframe on CRM's Opportunity form. This aspx page has form which submits data into the other database.
Requirement :
I would like when user clicks save button on CRM opportunity form ,aspx page should store the data in external database and opportunity form should also save all the changes on CRM form.
My Efforts :
Till now I have Iframed aspx page on CRM form.I am also submitting the form using OnSave event.
But the only problem is the form gets submitted but by the time it executes the complete code CRM form gets refreshed . End result is that Data on aspx page does not get stored in the external database.
What can be the other possible way to achieve this functionality ?
Thanks for taking time to read. Thank you in advance.
Option 1: The better solution is to do this from an opportunity post event plug-in. This ensures data consistency between CRM and external data (if required). Also you could use WCF or a web service to transmit the data to external DB.
Option 2: If you must use javascript you could (1) bind to opportunity form OnSave, (2) Prevent the form from submitting , (3) submit the iframe and (4) wait until it comes back and then (5) do another save to complete the action. This however might cause inconsistencies between CRM and external DB if opportunity save fails.
Here is a pseudo code example
function OpportunityOnLoad() {
IFRAME.OnReadyStateChange = function() {
// (4) Check success if possible
// (5) unbind save event and complete the opportunity save
Form.RemoveOnSave(OpportunityOnSave)
Form.Save();
}
//OnLoad
Form.AddOnSave (OpportunityOnSave);
}
function OpportunityOnSave(context) {
//(1) Save clicked
//(2) Stop save
context.PreventDefault();
//(3) Submit iframe form
IFRAME.Submit();
}
EDIT:
Regarding Q1 : unfortunately not.
Regarding Q2 :
This is a rough translation of the concept above into Javascript and CRM client side API.
I didn’t test it but it should put you on the right track.
Change the Params to match the iframe id, url etc.
also since you’re using an aspx you might experience cross domain issue that could be easily overcome if you’re browsing IE and not so easily overcome if you’re using CROME for example.
var IFRAME, SaveMode;
var FORM = Xrm.Page.data.entity;
var UI = Xrm.Page.ui;
var SaveModes = {
1 : "save",
2 : "saveandclose",
59: "saveandnew"
}
var Params = {
IframeBaseUrl : "",
IframeId : "IFRAME_test",
IframeFormId : "form1"
}
function OpportunityOnLoad() {
var sUrlparams = "?"; //add required params after ?
var IframeUrl = Params.IframeBaseUrl + sUrlParams;
IFRAME = UI.controls.get(Params.IframeId);
IFRAME.setSrc(IframeUrl);
IFRAME.Dom = document.getElementById(Params.IframeId);
IFRAME.add_readyStateComplete(OnAfterIfameSave);
FORM.addOnSave(OpportunityOnSave);
}
function OnAfterIfameSave() {
//SubmitSuccess indicates that the form has reloaded after a
//successful submit. You'll need to set this variable inside your iframe.
if (IFRAME.contentWindow.SubmitSuccess) {
FORM.removeOnSave(OpportunityOnSave);
FORM.save(SaveModes[SaveMode]);
}
}
function OpportunityOnSave(execObj) {
var evArgs = execObj.getEventArgs();
evArgs.preventDefault();
SaveMode = evArgs.getSaveMode();
IFRAME.contentWindow.document
.getElementById(Params.IframeFormId)
.Submit();
}
In javascript, I have an innerHtml element that I am trying to upload to my mysql database using a form in Laravel 4.
In the javascript, I have:
document.getElementById("myUrl").innerHTML = FPFile.url;
This is the url I would like to upload to my database.
Then, in the view, I have:
{{Form::hidden('myUrl',null, array(
'id' => 'myUrl',
));}}
This is my attempt to upload the url to the database as part of a form.
In my controller, I have:
$artist->image_path = Input::get('myUrl');
The column is called image_path, and the object in the view is 'myUrl'.
When I click submit for the form, url is not uploaded.
Do you see anything I have done wrong? Thank you for your help.
document.getElementById("myURL").value = FPFile.url;
ExtJS Version : 4.1.0
Answered - See my response below... quite silly really
I have a simple form with a few fields, one of them being of the xtype fileuploadfield. I listen for the click event on my form's save button in the Controller's this.control method. When the click event occurs, I run a method saveForm, which looks like this:
saveForm: function(button) {
/** Get the Window Object and retrieve the Form*/
var currentWin = button.up('window'),
form = currentWin.down('form');
/** Get the Form Object */
form = form.getForm();
/** ...continued... */
}
At this point in my method, I can console.log the form object, inspect the object's _fields and see my fileuploadfield and the path of the file I input in the field (i.e. C:\fakepath\somefile.png). I can also perform form.getField('upload-field-id'); to get the upload field element. The method form.hasUpload() returns TRUE.
The kicker is that when I call form.submit() and var_dump() the $_FILES array on my server, it is empty!
In the examples that I've seen of file uploading in ExtJS, the form submission happens via a handler function on the Save button in the view. As I like to keep logic for handling button presses in my controller, I'm hoping this is not my only option!
Any input would be greatly appreciated, thank you for your time.
I feel a bit silly, but the problem was pertaining to retrieving the form object from the button passed to my saveForm method.
Corrected:
In my ExtJS controller...
saveForm: function(button)
{
var currentWindow = button.up('window');
/** var form = button.down('form').getForm(); **INCORRECT** */
var form = button.up('form').getForm(); /** this is correct */
form.submit({
url : '/service/form/upload/format/json',
waitMsg : 'Uploading....',
success : function(form,o) {
alert(o.response.responseText);
},
failure: function(form, action)
{
console.error('form, action', form,action);
alert('failure');
}
});
}
In my back-end (Zend), my controller action is simply:
public function uploadAction()
{
var_dump($_FILES);
this->view->success = false;
}
As expected, my Chrome Inspector outputs the following upon clicking the save button:
Uncaught Ext.JSON.decode(): You're trying to decode an invalid JSON String:
{"success":false}array(1) {
["file-upload-field"]=>
array(5) {
["name"]=>
string(29) "TestImage.jpg"
["type"]=>
string(10) "image/jpeg"
["tmp_name"]=>
string(14) "/tmp/php7XfeLD"
["error"]=>
int(0)
["size"]=>
int(89799)
}
}
The server has successfully received the file upload!
This is most certainly a server side issue. ExtJS makes use of hidden components to submit a multipart form to the server. This indeed works as described in the guides, examples, and docs.
I am unfamiliar with var dump function you refer to above, but you need to make certain that your server side component is handling the multipart form submission correctly.