i have a custom object (CallReport__c) on this object i want to upload multiple files at a single time through visualforce page of the callReport__c custom object and the uploaded files should be saved in the callReport__c custom object
You can use apex:inputFile tag for this and store them into Attachments/Document object, if the files you are uploading are not too large, a controller can easily upload files into attachements/documents.. If you have to upload large files then use the html input type="file" tag and use visualforce remoting to upload them.
Let me know if this solves your issue or you need more info about this.
This is my Controller class
public class Attachment_Action_Function {
public transient String base64;
public Call_Report__c cr {get;set;}
public List<Attachment> mulfiles{get;set;}
public Pagereference gotonewpage(){
PageReference pageRef = Page.CallReport;
pageRef.getParameters().put('msg','success');
return PageRef;
}
public Attachment_Action_Function() {
mulfiles=new List<Attachment>();
}
public String getBase64(){
return base64;
}
public void setbase64(String base64){
this.base64 = base64;
}
public String fileName {get; set;}
public Attachment_Action_Function(ApexPages.StandardController controller){
this.cr = new Call_Report__c();
mulfiles = new List<Attachment>();
cr = (Call_Report__c)controller.getRecord();
}
public void saveFile(){
Attachment a = new Attachment(parentId = cr.id, Body = EncodingUtil.base64Decode(base64), name = fileName);
mulfiles=new List<Attachment>();
// mulfiles.AccountId= cr.Id;
mulfiles.add(a);
//insert a;
}
public PageReference saveinline() {
return null;
}
}
This is my Visualforce page, i am Inserting this code in a pre-defined callReport VF page.
<script type = 'text/javascript'>
var newWin=null;
function openLookupPopup()
{
var url="/apex/CallReport/";
alert('$$$$$$$$$$'+ur1);
newWin=window.open(url, 'Popup',height=500,width=600,left=100,top=100, resizable=no, scrollbars=yes, toolbar=no, status=no);
}
function closeLookupPopup()
{
if (null!=newWin)
{
newWin.close();
}
}
var maxStringSize = 6000000;
var attachmentList;
var j;
function uploadFiles()
{
input = document.getElementById('fileinput');
attachmentList = input.files;
if(j == undefined)
j = 0;
var file;
if(j < attachmentList.length)
{
file = attachmentList[j];
var name = file.name;
var reader = new FileReader();
reader.onload = function(e) {
var attachmentbodybase64 = window.btoa(reader.result)
console.log(attachmentbodybase64.length);
if(attachmentbodybase64.length > maxStringSize )
alert("File size is too large to handle");
else
{
j++;
saveFileAF(attachmentbodybase64, name);
}
}
reader.readAsDataURL(file);
}
else
{
console.log('this is end');
var url = window.location.origin + '/'+"{!$CurrentPage.parameters.Id}";
console.log(url);
window.location.href = url;
}
}
</script>
<script>
function test(){
var url="/apex/CallReport";
newWin=window.open(url, 'Popup','height=500,width=600,left=100,top=100,resizable=no,scrollbars=yes,toolbar=no,status=no');
console.log('$$$$$$$$$$'+ur1);
if (window.focus)
{
newWin.focus();
}
return false;
}
</script>
<input type= "file" Id= "fileinput" multiple="multiple" />
<apex:commandButton value="Upload" onclick="test(); return false;" />
<apex:actionFunction name="saveFileAF" action="{!saveFile}" oncomplete= "test()" rerender="form" status="uploading">
<apex:param name="base64File" value="" assignTo="{!base64}"/>
<apex:param name ="fileName" value="" assignTo="{!fileName}"/>
</apex:actionFunction>
<apex:actionStatus id="uploading" >
<apex:facet name="start" >
<img src="/img/loading.gif" />
</apex:facet>
</apex:actionStatus>
note:- When i privew my VF page its giving me ERROR:- Invalid conversion from runtime type Account to Call_Report__c .
But when i remove the code:--> cr = (Call_Report__c)controller.getRecord(); from the Constructor of the Controller class the Object then the Files are being Uploaded but where it is being saved i did'nt found it.
the CallReport__C Object is in a MASTER DETAIL Relationship with Account Object.
and i want to save the Files which are being Uploaded in the CallReport Custom Object..
It seems that on your page you are using standard controller as Account. Please send the whole code of your visualforce page. And when are saving the record its probably getting saved in Attachment which may be viewed in related list of Account.
So, instead of using this, you can call the javascript method which reads the file and then use a remote method to upload the file to Attachments.
For uploading use this code snippet.
In Visualforce Page :
<input type="file" name="pic" accept="image/*, audio/*, video/* " id = "upFile" value="fileupload" class = "reqFiles"/>
<apex:commandButton value="Upload" onclick="uploadFile();" />
Script :
<script>
var blobfile;
var fbody;
function getAsText(readFile) {
var reader = new FileReader();
// Itereate over readFile to upload multiple files. and then call this method one by one, For now I have used just 1 file
reader.readAsDataURL(readFile);
reader.onload = function(evt) {
var fileString = evt.target.result;
blobfile = fileString;
var fileProp = {fileName : fbody.name, fileType : fbody.type , file : blobfile.split(",")[1]};
Visualforce.remoting.Manager.invokeAction('{!$RemoteAction.Attachment_Action_Function.saveFile}'
, fileProp
, function(result, event){
console.log('result ===== '+result);
if(event.type === 'exception' ) {
} else {
console.log('upload successful');
}
}
);
};
}
function uploadFile() {
fbody = document.getElementById('upFile').files[0];
console.log('fbody ==== ', fbody);
getAsText(fbody); // For multiple, send the whole List of Files
}
</script>
In script in uploadFile() method if you notice, I have used index of file, Instead of that you can itereate over files to make it work for multiple file upload. I would suggest you to try this code snippet for uploading single file and then modify if to make it work for multiple files as well.
Let me know if this solves your issue or any additional info is needed.
Its Not giving me the ERROR, but when i upload the files its not saved to any of the object neither the Call_Report__c custom object nor to the Account Object Which is in a MASTER DETAIL relationshp with the Call_Report__c Custom Object
You will need to populate the ParentId Field in the Attachment object before inserting it. As you are using standard controller as Account, You can pass it dirently from javascript methods we just created. So, Change these following lines :
This will add the attachment into the related list of account. If you want to relate the Call_Report__c record Id then use this accountId inside remote method to get the Call_Report__c Id and then add it to the ParentId field.
Can you debug accountId in this method and also do a console.log("{Account.Id}"); in JavaScript and tell me the results. Also please post the latest code here.
i also get the ERROR through debug log Line: 2, Column: 22 Method does not exist or incorrect signature: void saveFile() from the type CallReportController
I used your code and uploaded a file into Attachment and it got inserted into Related list of Account.. I have few questions :.
1. As you have used Standard Controller as Account, is there any particular reason for using that(please try to explain the use case)? 2. How are you using this Page?, I mean from where does this the page get opened? I added a detail view Button on Account through which I went into this Page and uploaded the File. It got uploaded because when we passed the Account.Id From javascript, it has to get the value from record which would be missing if you Preview the page directly(File won't be uploaded in this case and you may get error in controller : Invalid Id). 3. Add a button on Account with Content Source as Visualforce Page and choose your page. In detial page of Account click on this button, it will open the page. Now try to upload the File 4. Kindly check on these points as its working on my end. Use this code below :
Visualforce Page :
<apex:page standardController="Account" extensions="Attachment_Action_Function">
<apex:form>
<apex:pageBlock>
<apex:pageBlockSection title="Upload Files">
<script>
var blobfile;
var fbody;
function getAsText(readFile) {
var reader = new FileReader();
console.log('inside getAsText ========= ', readFile);
reader.readAsDataURL(readFile);
reader.onload = function(evt) {
var fileString = evt.target.result;
blobfile = fileString;
var fileProp = {fileName : fbody.name, fileType : fbody.type , file : blobfile.split(",")[1]};
Visualforce.remoting.Manager.invokeAction('{!$RemoteAction.Attachment_Action_Function.saveFile}'
, fileProp
, "{!Account.Id}"
, function(result, event){
console.log('result ===== '+result);
if(event.type === 'exception' ) {
} else {
console.log('upload successful');
}
}
);
};
}
function uploadFile() {
fbody = document.getElementById('upFile').files[0];
console.log('fbody ==== ', fbody);
getAsText(fbody); // For multiple, send the whole List of Files
}
</script>
<input type="file" name="pic" accept="image/*, audio/*, video/* " id = "upFile" value="fileupload" class = "reqFiles"/>
<apex:commandButton value="Upload" onclick="uploadFile();" />
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page>
Controller :
public class Attachment_Action_Function {
public transient String base64;
//public Call_Report__c cr {get;set;}
public List<Attachment> mulfiles{get;set;}
public void gotonewpage(){
// PageReference pageRef = Page.CallReport;
// pageRef.getParameters().put('msg','success');
// return PageRef;
}
public Attachment_Action_Function() {
mulfiles=new List<Attachment>();
}
public String getBase64(){
return base64;
}
public void setbase64(String base64){
this.base64 = base64;
}
public String fileName {get; set;}
public Attachment_Action_Function(ApexPages.StandardController controller){
// this.cr = new Call_Report__c();
// mulfiles = new List<Attachment>();
//cr = (Call_Report__c)controller.getRecord();
}
/** public void saveFile(){
Attachment a = new Attachment(parentId = cr.id, Body = EncodingUtil.base64Decode(base64), name = fileName);
mulfiles=new List<Attachment>();
// mulfiles.AccountId= cr.Id;
mulfiles.add(a);
//insert a;
}*/
@RemoteAction
public static void saveFile(Map<String, String> filePropMap, String AccountId) {
String file;
String filename;
String fileType;
for(String prop : filePropMap.keySet()) {
file = filePropMap.get('file');
fileType = filePropMap.get('fileType');
filename = filePropMap.get('fileName');
}
System.debug('AccountId ========= ' + AccountId);
Attachment attObj = new Attachment(Body = Blob.valueOf(file), name = filename, ParentId= AccountId);
//System.debug('ParentId---->>'+AccountId);
insert attObj;
}
public PageReference saveinline() {
return null;
}
}
Thanks for the info, its still unclear as why Account is the standard object. Is it because you are accessing the page from standard Account Page?
When you say it generates CallReport, from where does this page gets opened?
If you need to Add it to Call_Report__c related list then you will need the Id of the Record in Call_report__c, If you can get it using your data then get the Call_report__c Id and add it to ParentId field in Attachment before inserting.
This makes things clear. All you need to do now is to get the Call_Report__c Id using the Account Id. And use this Call_Report__c Id in place of AccountId in ParentId for insertion of Attachment.
So, I would like to understand the relationship between these two objects. As you mentioned there is a Master Detail Relationship, so which is child of what? Is there a field on Account with a Master detial to Call_report__c ? If yes you can directly get the value of that field by Account.Call_Report__c.
// get callReportId
Attachment attObj = new Attachment(Body = Blob.valueOf(file), name = filename, ParentId= callReportId);
For multiple, there are multiple ways, it depends on the requirement on how you want it to be :
1. You can create a table like structure where you can add multiple rows, Each row consisting of one file. And one button on click of which all files gets uploaded. (you will need lot of code changes for this).
2. Select multiple files on the browse window which appears on click of choose file. (For this you will need a little logic change in javascript).
For adding the Multiple Files, i want to select the multiple files on a single time, like when we try to upload the files we select only one file is selected for uploading but i want to select more than one file at a time..
I have modified the code to make it work for multi file upload.
Visualforce Page
<apex:page standardController="Account" extensions="Attachment_Action_Function">
<apex:form >
<apex:pageBlock >
<apex:pageBlockSection title="Upload Files">
<input type="file" name="pic" accept="image/*, audio/*, video/* " id = "upFile" value="fileupload" class = "reqFiles" multiple="true"/>
<button name="Upload" onclick="uploadFile();return false;" > Upload </button>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
<script type="text/javascript">
var blobfile;
var fbody;
var fbodyArray=[];
var filePropArray = [];
function getAsText(readFile) {
var fileIndex = 0;
for(var i=0 ; i < readFile.length; i++) {
var reader = new FileReader();
reader.readAsDataURL(readFile[i]);
reader.addEventListener("load", function () {
var fileString = this.result;
blobfile = fileString;
var fileProp = {fileName : fbodyArray[fileIndex].name, fileType : fbodyArray[fileIndex].type , file : blobfile.split(",")[1]};
filePropArray.push(fileProp);
if( fileIndex < fbodyArray.length) {
fileIndex++;
}
}, false);
}
console.log('filePropArray before remoting=======',filePropArray);
Visualforce.remoting.Manager.invokeAction('{!$RemoteAction.Attachment_Action_Function.saveFile}'
, filePropArray
, "{!Account.Id}"
, function(result, event){
console.log('result ===== '+result);
if(event.type === 'exception' ) {
} else {
console.log('upload successful');
}
}
);
}
function uploadFile() {
fbodyArray = document.getElementById('upFile').files;
// For multiple, send the whole List of Files
getAsText(fbodyArray);
}
</script>
</apex:page>
Controller :
public class Attachment_Action_Function {
public transient String base64;
//public Call_Report__c cr {get;set;}
public List<Attachment> mulfiles{get;set;}
public void gotonewpage(){
// PageReference pageRef = Page.CallReport;
// pageRef.getParameters().put('msg','success');
// return PageRef;
}
public Attachment_Action_Function() {
mulfiles=new List<Attachment>();
}
public String getBase64(){
return base64;
}
public void setbase64(String base64){
this.base64 = base64;
}
public String fileName {get; set;}
public Attachment_Action_Function(ApexPages.StandardController controller){
// this.cr = new Call_Report__c();
// mulfiles = new List<Attachment>();
//cr = (Call_Report__c)controller.getRecord();
}
/** public void saveFile(){
Attachment a = new Attachment(parentId = cr.id, Body = EncodingUtil.base64Decode(base64), name = fileName);
mulfiles=new List<Attachment>();
// mulfiles.AccountId= cr.Id;
mulfiles.add(a);
//insert a;
}*/
@RemoteAction
public static void saveFile(List<Map<String, String>> filePropMap, String accountId) {
String file;
String filename;
String fileType;
List<Attachment> listAttachment = new List<Attachment>();
for(Map<String, String> prop : filePropMap) {
file = prop.get('file');
fileType = prop.get('fileType');
filename = prop.get('fileName');
listAttachment.add(new Attachment(Body = Blob.valueOf(file), name = filename, ParentId= accountId));
}
insert listAttachment;
}
public PageReference saveinline() {
return null;
}
}
Please use the above code for uploading multiple files. Please note that file readers sometimes doesn't work unexpectedly, you will need to handle those exceptions.
Also, check on the ParentId field as I'm still using the AccountId for this demonstration.
i am able to select the multiple files but when i click on upload the file is not uploaded neither to the Account Object nor to the Call_Report custom object.
i want that after uploading the files should be seen below.. please guide me .
Hi Asad, I would like to know from where are you accessing the page? Is it from the detail page button or from somewhere else. If Account Id is not present in the URL parameter then it will not get attached to the account. Opening the VF page via detail page button on Account will solve this issue.
Since the Account and the Call_Report__c are in a master Detail relationship. callReport will only be created when there is an existing Account.
I go to one of the Account and on that Account Detail page, there is a button called CALLREPORT , when i click on this button this will redirect me to the callReport page to create CallReport of that Account.
The Button to create the call Report is present on Every Account Detail Page.
It should be working now. Please double check it, sometimes the javascript file reader doesn't work properly due to which the records are not created properly as I mentioned earlier. Try to do it again, it should be working as its working on my end too.
You can use apex:inputFile tag for this and store them into Attachments/Document object, if the files you are uploading are not too large, a controller can easily upload files into attachements/documents.. If you have to upload large files then use the html input type="file" tag and use visualforce remoting to upload them.
Let me know if this solves your issue or you need more info about this.
Thanks.
note:- When i privew my VF page its giving me ERROR:- Invalid conversion from runtime type Account to Call_Report__c .
But when i remove the code:--> cr = (Call_Report__c)controller.getRecord(); from the Constructor of the Controller class the Object then the Files are being Uploaded but where it is being saved i did'nt found it.
the CallReport__C Object is in a MASTER DETAIL Relationship with Account Object.
and i want to save the Files which are being Uploaded in the CallReport Custom Object..
It seems that on your page you are using standard controller as Account. Please send the whole code of your visualforce page.
And when are saving the record its probably getting saved in Attachment which may be viewed in related list of Account.
Thanks
You are using Account as standard controller and then assigning the Call_Report__c object to Account object, which is incorrect.
Also, if you look at these lines, its not actually assigning anything to 'base64' and 'fileName' variables.
So, instead of using this, you can call the javascript method which reads the file and then use a remote method to upload the file to Attachments.
For uploading use this code snippet.
In Visualforce Page :
Script :
In Controller :
In script in uploadFile() method if you notice, I have used index of file, Instead of that you can itereate over files to make it work for multiple file upload. I would suggest you to try this code snippet for uploading single file and then modify if to make it work for multiple files as well.
Let me know if this solves your issue or any additional info is needed.
Thanks.
Attachment attObj = new Attachment(Body = file, name = filename);
file = filePropMap.get('file');
Try changing it to : Attachment attObj = new Attachment(Body = Blob.valueOf(file), name = filename);
Thanks
Invalid conversion from runtime type Account to Call_Report__c
(Call_Report__c)controller.getRecord()
Its Not giving me the ERROR, but when i upload the files its not saved to any of the object neither the Call_Report__c custom object nor to the Account Object Which is in a MASTER DETAIL relationshp with the Call_Report__c Custom Object
You will need to populate the ParentId Field in the Attachment object before inserting it. As you are using standard controller as Account, You can pass it dirently from javascript methods we just created. So, Change these following lines :
In Visualforce Page :
In Controller :
This will add the attachment into the related list of account. If you want to relate the Call_Report__c record Id then use this accountId inside remote method to get the Call_Report__c Id and then add it to the ParentId field.
Thanks.
Correction to previous reply :
public void saveFile(Map<String, String> filePropMap,String accountId)
Line: 2, Column: 22
Method does not exist or incorrect signature: void saveFile() from the type CallReportController
I used your code and uploaded a file into Attachment and it got inserted into Related list of Account.. I have few questions :.
1. As you have used Standard Controller as Account, is there any particular reason for using that(please try to explain the use case)?
2. How are you using this Page?, I mean from where does this the page get opened? I added a detail view Button on Account through which I went into this Page and uploaded the File. It got uploaded because when we passed the Account.Id From javascript, it has to get the value from record which would be missing if you Preview the page directly(File won't be uploaded in this case and you may get error in controller : Invalid Id).
3. Add a button on Account with Content Source as Visualforce Page and choose your page. In detial page of Account click on this button, it will open the page. Now try to upload the File
4. Kindly check on these points as its working on my end. Use this code below :
Visualforce Page :
Controller :
Thanks.
Thanks for the info, its still unclear as why Account is the standard object. Is it because you are accessing the page from standard Account Page?
When you say it generates CallReport, from where does this page gets opened?
If you need to Add it to Call_Report__c related list then you will need the Id of the Record in Call_report__c, If you can get it using your data then get the Call_report__c Id and add it to ParentId field in Attachment before inserting.
Thanks
Please suggest me How to Insert the Multiple Times at a single Click
This makes things clear. All you need to do now is to get the Call_Report__c Id using the Account Id. And use this Call_Report__c Id in place of AccountId in ParentId for insertion of Attachment.
So, I would like to understand the relationship between these two objects. As you mentioned there is a Master Detail Relationship, so which is child of what? Is there a field on Account with a Master detial to Call_report__c ? If yes you can directly get the value of that field by Account.Call_Report__c.
1. You can create a table like structure where you can add multiple rows, Each row consisting of one file. And one button on click of which all files gets uploaded. (you will need lot of code changes for this).
2. Select multiple files on the browse window which appears on click of choose file. (For this you will need a little logic change in javascript).
For adding the Multiple Files, i want to select the multiple files on a single time, like when we try to upload the files we select only one file is selected for uploading but i want to select more than one file at a time..
I want to achieve This Functionality
Select multiple files on the browse window which appears on click of choose file..
I want to add the files on the call_Report__c (Custom object), but i am unable to do so.
And when i execute the method saveFile on the DEBUG CONSOLE like
CallReportController c=new CallReportController();
CallReportController.saveFile();
then i am getting the
ERROR:-Line: 2, Column: 22
Method does not exist or incorrect signature: void saveFile() from the type CallReportController
I have modified the code to make it work for multi file upload.
Visualforce Page
Controller :
Please use the above code for uploading multiple files. Please note that file readers sometimes doesn't work unexpectedly, you will need to handle those exceptions.
Also, check on the ParentId field as I'm still using the AccountId for this demonstration.
Let me know if any further info is required.
Thank you.
i am able to select the multiple files but when i click on upload the file is not uploaded neither to the Account Object nor to the Call_Report custom object.
i want that after uploading the files should be seen below..
please guide me .
and i am really thankfull the way to supported me
thanks
Asad
I would like to know from where are you accessing the page? Is it from the detail page button or from somewhere else.
If Account Id is not present in the URL parameter then it will not get attached to the account. Opening the VF page via detail page button on Account will solve this issue.
Thanks.
Since the Account and the Call_Report__c are in a master Detail relationship.
callReport will only be created when there is an existing Account.
I go to one of the Account and on that Account Detail page, there is a button called CALLREPORT , when i click on this button this will redirect me to the callReport page to create CallReport of that Account.
The Button to create the call Report is present on Every Account Detail Page.
It should be working now. Please double check it, sometimes the javascript file reader doesn't work properly due to which the records are not created properly as I mentioned earlier. Try to do it again, it should be working as its working on my end too.
Thanks