Yesterday evening I spoke at Dutch Dynamics Community event, on invitation by my dear friend Luc van Vugt, and the topic was control add-ins for NAV 2013 R2. Of course, this automatically meant that the audience should see more JavaScript code than C# or C/AL, and that it should be something both fancy and useful.
So how about this: you drag and drop a file onto an NAV page, and the file is automatically uploaded and stored in a BLOB field in the NAV database? And yes, it does the same no matter if you call it from the Windows or the Web client. And yes of course, no external components or dependencies needed.
As I promised, I would make all the source components available for download after the sessions, and if you just want to take the components, here they are, ready to download, install and abuse:https://vjeko.com/wp-content/uploads/2014/03/DragDrop.zip
If you want to know how this thing works and why, read on. Otherwise, just download the thingy, install it (the instructions are included with the file) and abuse it to your fancy.
Okay, I see you decided to stay. Good.
I’m sure I don’t need to explain the part about how to create an assembly including the interface that explains to the C/AL compiler which events and methods are supported on the new component. This makes my job easier here, so I’ll focus on the JavaScript right away.
This piece of code appends some HTML to the control:
- DIV with ID #drop-files to act as a drag & drop host control. It is styled using the embedded CSS
- DIV with ID #drop-text, which is displayed only if the image is not present
- IMG with ID #drop-img, which shows the image if it is present
- DIV with ID #drop-clear, which acts like a button and invokes the C/AL trigger to remove the image from the BLOB
This function receives the image represented as data URI. If there is data, the image is bound as the source of the #drop-img element. If there is no data, image is hidden, and text is shown.
This is the workhorse, from the JavaScript end. This piece of code first enabled the data transfer for the document, and binds a function to respond to the drop event of the DIV control created earlier. The event receives the collection of files (yes, it is technically read to receive multiple files) and then for each file in the collection it initiates the download through the readAsDataURL method. Also, the FileReader instance responds to the onload event by receiving the image data represented as data URI, checks whether the data is indeed image, and does two things – it calls the SendData function I explained earlier and then calls the NAV DataRead trigger to pass the received Data URI image.
The remaining JavaScript code is there to enable drag and drop effects, clicking the DIV to send the request to clear the image, and to instantiate the control. Let’s move to C/AL.
This function is called from the DataRead event trigger, and it receives the text representing the image as data URI. It first checks whether the data URI is correct through a regular expression. If it is, then it takes the part of the match that represents pure image data in Base64, converts it to binary, loads it into a stream, and then copies that stream into the BLOB. Here, the image data is stored into NAV.
One thing remains: to send image data to JavaScript if it exists.
This function loads the image data into the stream, then loads the stream into an Image object to check its format, which is necessary for the data URI that it must return. It starts constructing the data URI by specifying which image format it is, and then finalizes it by converting the memory stream into the Base64 encoded string.
Finally, this method calls the control add-in, and invokes its SendData function. This in turn calls the same SendData function in JavaScript that I’ve explained earlier.
And that’s all. Simple, and functional.
Now, if you haven’t downloaded the demo, don’t waste any more time, just grab your copy and put it to work. If you find it useful, please come back to tap my shoulder and to share with the world how happy you and your customer are with this component and with how much time it saved in your implementation. Cheers!
Vjeko, great post!!
Defenetly gonna try this one :))
Thanks Vjeko!
Again, great presentation yesterday and i’ll make good use of your examples!
Thanks fot the intresting session and sharing this expertise. Great stuff these Javascript Control Add-Ins. I was looking for a advanced “Hello World” example for a while and found it in this solution. Time to start upgrading my obsolete HTML and JavaScript skills now.
Go Vjeko Go!! Thanks for the examples and the clear instruction!
TAP TAP TAP TAP 🙂
Thanks for another great session, Vjeko!
Thx for this great example code. If I want the dragged file to be saved on the server in a shared folder, I presume the code to copy this file should be placed in the JavaScript part?
Hi Luc,
I wouldn’t do this via Javascript since the client typically will not have access to the server file storage.
The solution is quite simple though by modifying the C/AL code;
Instead of this code in the SavePicture function:
Rec.Picture.CREATEOUTSTREAM(OutStr);
COPYSTREAM(OutStr,MemStream);
Rec.MODIFY;
It can easily be changed to something like this:
Image := Image.FromStream(MemStream);
Image.Save(,ImageFormat.Png); // If you want to save it as .png file
With these variables declared:
———————————————————–
– Image = DotNet “‘System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’.System.Drawing.Image”
– ImageFormat = DotNet “‘System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a’.System.Drawing.Imaging.ImageFormat”
Actually, once you have it in the stream, no need to load it into an image. Just create a file, then call the CREATEOUTSTREAM on the file. Also, change the regex to catch aby binary fike, not just images.
Dear friend, thanx for having been with us and sharing your expertise. Cu soon. B rg Luc
Pingback: Drag and Drop File Upload for Microsoft Dynamics NAV 2013 R2 | Pardaan.com
Vjeko, great post!
But still have an issue with large images.
It works fine with small images (<48K)
When dropping larger images (in the webclient) , the following error occured: "Communication with the server failed, and the content cannot be displayed. Refresh the page or open a new browser window."
Monitoring with firefox + firebug results in the following http error 413: request entity to large.
Any ideas how to solve this?
Thanx,
Harry
Great catch! About the solution ideas, I have two, one of which I am not quite sure about. One is to try to play with the amount of data the NST can receive. The other is to send data to NAV in smaller chunks. If I get time, I’ll provide both, but cannot promise when it will be.
Is it possible for u to provide this solution also for Nav 2013/Visual Studio 2010 ?
Yes, it is possible. I’ll do that at my earliest.
Hi Vjeko, this seems a very good solution!
We’d like to use it, was a version for NAV2013 published in the end?
Thanks
Daniele
Hi Daniele, thanks for the comment! I am currently working on a new version which will work on all (2013, 2013R2, 2015) versions, will support multiple-file drop, and will fix the issue with >40KB upload through web client. I’ll publish it on my blog very likely this week, next at latest. Is that okay?
Thanks for fast feedback, looking forward to it!
I will keep monitoring the blog 🙂
Now I can’t wait to see your solution and how you solved the >40Kb issue 🙂
Hi, are you still planning on upgrading the extensions?
Hi, are still planning to update the extension?
Yes, I am planning on doing that, just don’t ask me when exactly – time is not really on my side…
Hi thanks for the the solution ! Works really cool.
I just wish I had the skills to modify so I can also drag / drop e-mails 🙂
Cheers from Denmark,
Povl
Thanks again. I learned a bit of JavaScript, and modified your script so it can be used for any datatype and also get the filename, type, size and blob to a new document table !
Some of the best things in life are free!
Dragging Outlook mails have proved too big a challenge for now
Hi Povl, is it possible if you could share your script? thanks.
Hello Povl!
Could you please share your modified solution, if possible?
Many thanks!
Pov
Could you share your code?
thanks
The code is attached to this post. Can you not find it?
I was looking for Povl’s modified version, cannot seem to find it?
Hi,
we also have the file size problem, so we can’t upload files >48 KB.
I tried to send the BASE64 String step by step in “smaller” packages and merge them in NAV.
But this also occurrs the 413 Too Large error.
Have anyone an idea?
The NAV / Web Client configuration file we also modified. We changed the chunk size, but this has no effect.
Also, we tried some configuration modifications on IIS but we get everytime the 413 error if we upload files >48 KB.
Hi,
The issue with the error message 413 is, that the number of Bytes exceeds an internal buffer. You may split the data into smaller chunks (and also use File.Slice() API to support very large data files).
However, all communication between the browser and the IIS via the Microsoft.Dynamics.NAV.InvokeExtensibilityMethod() is asynchronous, meaning that the JavaScript call to InvokeExtensibilityMethod returns immediately – long before the actual trigger gets executed on the Dynamics NAV Server.
The Dynamics NAV Control Add-in API does not expose information about when an InvokeExtensibilityMethod() call is complete and the Dynamics NAV Server is done executing the Trigger. This is needed to synchronize the code in the control add-in.
You may play around to only send small chunks and signal the web browser after data has been processed. This may also need to include code to decouple method calls and avoid a ping-pong call stack between C/AL and JavaScript using setTimeout().
Cheers
Carsten
Hi Vjeko, thanks for all the very useful demonstrations and How-To videos online!
I’m hoping you might be able to shed some light on a problem I’m having trying to display a c# winform control add-in in the web client. I have a calendar control add-in created in C# that runs ok in windows client but not in web client, this was understandable as there was no manifest file and interface C# program containing triggers/methods.
So I created a manifest file that invokes a C# interface program method which then embeds the original C# calendar program packaged as an activeX into the web client as a HTML object(similar to your how-to video on WMP). This method works ok for a simple HelloWorld() method but not for a winform createcontrol() method. Do you know is it possible to achieve what I’m trying to do i.e. embed a c# winform into the web client?
Thanks!
Pingback: Directions US Presentation and Files | Vjeko.com
Based on Carsten’s suggestion, i managed to get a file-upload working with files much larger than the 48 Kb limit.
It basically means doing these steps:
1. Call an event “OnFileUploadInitiate” from the Add-in
2. This event in NAV on it’s turn saves the number of files to receive in a global variable and fires a function in the Add-in to start uploading a single fileblock (UploadSingleFileBlock(1,1))
3. The Add-in then starts the upload for the first fileblock with a size as specified in advance (windows clients are allowed to send much bigger chunks then the Web Client). It’s using a different event that i called “UploadFileBlock” which sends this file block to NAV with a few additional parameters (CurrentFileCount, BlockSequence, BlockData, TotalBlocks)
4. Based on the information received NAV decides if it needs to fire the same function in the Add-in again by incrementing either the fileblock or filecount (i.e. UploadSingleFileBlock(1,2))
5. It keeps repeating this process until all blocks for all files are received.
Key thing here is that the Control Add-in should Always be in control of sending the blockdata.
At first I tried to try a kind of ‘pull’ scenario so NAV pulls the data from the Add-in, but this Always failed. I don’t know the reason for this, but i’m guessing it has to do with the fact that NAV is in fact unaware of the Web Client (since there’s no active connection) and therefore fires multiple events at once to the control add-in in parallel.
When the Control Add-in is in charge of firing the events and sending the data, NAV only has to listen and comply to the request.
Hope this helps for anyone still fighting the issue.
Hi ptijsma,
I have the same issue on my Addin, on a normal NAV Client all works fine, when using the same addin in Webclient I get the communication error … Could I get your solution to help me out ?
PS, Vjeko, again BIG kudos for your blog, with the example I had 99% of my scope covered 🙂
Hi Vjeko, thanks for this post. I tried to use your control and I get this error message “An error has occured in the script on this page”…. do you want to continue running scripts on this page. Any suggestions?
User has full permission on client and server. I’m using version IE8. Could it be IE version?
Regards
Amit
Could be IE version, I am not quite sure. I haven’t tested it on IE8. Can you try it with a higher version?
Thanks Vjeko, will try to upgrade IE version.
HTTP 413 has been resolved with CU 10 for Microsoft Dynamics NAV 2015.
NAV Development Team bounded the WCF MaxReceivedMessageSize to system.web/httpRuntime maxRequestLength.
A zillion thanks to Vjeko to drive the NAV development world into the sky. And higher.
Pingback: Client Add-in can fail with communication error (HTTP 413) in the Microsoft Dynamics NAV 2015 Web Client – 8/26, Dynamics NAV Team |
Hi all, I’m finding the possibility of drag and drop very interesting and I got Vjeko’s solution to work, thanks for that.
But I’m quite interested in povl’s adjustment to be able to drag and drop any file.
Is that adjustment posted somewhere as well?
Thanks,
Rob
Hi,
How much change this code to Drag and Drop any type of file not only Images? I would like to store to a Record a Drag and Drop file.
Anyone can have article for it?
Thank you.
I’d like to know that too
Hi,
Very nice article! If saving to disk, is there any way to extract the original filename?
Thanks
Oscar
StackOverflow knows an awful lot of things: http://stackoverflow.com/questions/857618/javascript-how-to-extract-filename-from-a-file-input-control
Thanks but I don’t understand what to put in getElementById(”)
I have tried all id:s I can think of. Jquery seems a little different than the standard file input
Congratulations Vjeko, for this excellent article!
What if you just to drop a web link to a file (e.g. from O365 Sharepoint) and record the link in NAV, instead of the full physical file? Would it be possible with a tweak of your demo code?
Many thanks
Thanks! I am pretty sure it would work. Some googling + stackoverflowing would surely tell you how.
It sure would be possible.
Hi Vjeko! tried to create use page 59901 in my NAV 2017 “Items List” page as a factbox, and got in the RTC “The metadata object 59901 was not found.”. Then tried to compile the 59901 Item Picture Factbox object and got an error for the “CREATEOUTSTREAM” unknown variable… And with my restricted NAV license, can’t even open it in design mode… Any ideas?
Error No. Object Type Object ID Object Name Error Type Function/Trigger Line No. Description
1 Page 59901 Item Picture FactBox Error SavePicture 5 You have specified an unknown variable. CREATEOUTSTREAM Define the variable under ‘Global C/AL symbols’.
JL: Maybe it is because NAV2017 changes “Picture field” type. Try to add a new BLOB field in Item table and CREATE OUTSTREAM will work again. I just tried it on NAV2017
Hello Vjeko:
thanks for your wonderful function….I have loaded into NAV2016 but does not seem to work. We would be interested in contracting with you to load and adjust this function a little for our NAV2016 application.
Hi Vjeko,
any idea of how to implement this to Business Central?
Hi Robert,
Yes, this can be done in Business Central too, mostly the same way it has been done in NAV. I don’t remember what I did in the C/AL part, but if I used any of .NET classes, they are not needed any more because whatever they do can certainly be replaced either with AL or done in JavaScript. I am thinking of redoing this control add-in for Business Central.
Remake BC365 Maybe with https://www.dropzonejs.com/? 🙂 I’m trying it right now, but I’m not so good programmer and there are not many examples of BC365 ControlAddIns yet on the www.
Aaah, the good old evergreen Drag and Drop. You wouldn’t believe how many times I’ve set out to do an update on this one, but I never did. No promises here…
Hi Vjeko,
Nice Post , Liked file, but is that only takes image drag and drop, how about the file drag and drop,
Need some help on files drag and drop.
Thanks,
Rajesh
Hi Rajesh,
This is something that people often ask, but there is no difference in dragging and dropping images or any kind of files. Images are binary files, and this shows you that you can handle any kind of file out of the box. If what you are trying to do is show a preview of any kind of file (PDF, Word, Excel, PowerPoint) then this is a completely different topic, and it will require you to use a library which can do the preview for you.
Hey, I know this was done a while ago… not sure if I’ll see a reply…. but I was wondering if it would be easy to adapt this to the new ControlAddin object brought into use in the new AL development environment for recent versions of NAV/Business Central?
Yes, of course it can be done, however I never make any promises here on my blog. If I get to do it, I’ll do it, if I don’t, then I don’t. Keep in my that this blog is my personal time and personal effort and is for free, and what you see is what you get.
Its very good. we need to user for this.
Hi Vjeko,
I have done the steps same mentioned in the Remade file from Drag Drop folder. After I don’t know how to test. I tried to drag the documents to NAV 2018 window, but no response.
I am using NAV 2018 trial version. I want drag and drop documents/files to NAV and vice versa.
I am not sure what’s going wrong, where, or why – I have difficulties visualizing what you are doing exactly. Does the control add-in show in the page? If yes – what happens when you drag a document onto the control add-in?
Hi Vjeko.
I actually implemented my own dropzone functionality in JS (which work perfectly in a web client) before I saw your solution. I began searching for other solutions when I tried my dropzone in a RTC client and unfortunately found that I could not drop files. I am somehow simply not allowed to drop any files in the RTC client. I get the “forbidden” cursor as soon as the file that is being dragged hits some of the RTC client windows.
Do you have any idea of what is happening? I also downloaded your solution and tried that one, but with the same result unfortunately. In a C# control add in solution there should be a Control.AllowDrop property which should enable file drops but I can’t find anything equivalent for a JS solution. Is there something I have misunderstood?
Best regards
Sebastian
I have the same problem. I can not drop files in desktop client. But it works in webclient.
The desktop client is embedding Internet Explorer and then loads HTML from local filesystem using file protocol. Read more about this protocol here: https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/jj710207(v=vs.85)
My assumption is that some IE security restrictions could be interfering with this.
I love this functionality, works on NAV 2018. But, can you tell me how can I make it work for any type of file, not only images?
Dragging and dropping works for any kind of file. Preview only for images. There is no magic bullet how to make it work for “any type of file” – you must program for that.