In the second part of this tutorial we’ll add more ajax powered functionality to modals. You’re going to learn how to:
upload files via ajax
display notifications after modal data has been saved
view stored data in a table
ajax reload table after modal data has been saved
make sure that the modal opens when button is dynamically generated
First part of this tutorial can be found here. This tutorial relies on the first part, so I expect you to read it and code your solution before starting part two. All the sources for this tutorial can my found in my Github repository.
Uploading files via ajax
In its current state it’s impossible to upload files. Since uploading files is a likely scenario I’ll show you how to do that.
We start by adding a picture field for our contact:
Then we modify modal view to show picture upload form:
Right now our new field is visible, but it won’t be sent along other data. It’s caused by the way we sent it. We use
serialize() jQuery methods, which won’t work with files (learn why here).
serialize() method creates a URL-encoded string contain all fields, but the data from file inputs is omitted. We’ll replace it with
FormData. It is a data structure which can be used to send whole forms using ajax. Most importantly, we can use it to send files.
That’s it! You can send files via ajax using Bootstrap modals.
Showing notification on success
User opens modal, fills in the form, clicks “Save” button, modal closes, but nothing happens. Page is not refreshed. There is no notification. User doesn’t have any clue wheter it worked or not. I’ll show you how to fix it.
There are a couple of ways we can go about this. I’m going to show you how to solve this by showing a notification. In terms of UX user will clearly see that the action succeeded.
Simple version – plain text
In cases like this I like to place empty element inside a view. It’s a placeholder which we will use to display the notification. It helps us control how and where it’s displayed.
div to your layout:
Let us just put some static text into notification area:
That’s it for the easy version. All you do is to put the text inside container. You can think of more complicated variations e.g. you can put messages into modal data attributes and retrieve it from these data attributes. You can also return messages from your action, so you could use response data to display appropriate mesage.
Advanced version - ajax notifications
This is a more complicated scenario, but also it allows us to do more in certain aspects. We’ll generate correct messages from within action. After that messages will be fetched by another ajax request. We are also going to display notifications using alert component available in Bootstrap.
We’ll start the same way as we did in “simple” chapter. Let’s add a placeholder element to layout.
Now, we have to create notifications somewhere. As you read earlier we’ll make it happen inside action.
Because the data dissapears after it’s retreived we need to take care of possible nulls. However, we’ll make it a bit easier and more reusable by creating helper method:
Create notification on success:
As you see, we need to create new view file. It will render notifications. This time it won’t display simple plain text messages. We are going to create nice Bootstrap powered alerts:
It works now, but our work is not done yet. Did you notice that I’ve hardcoded URL to notifications action inside
site.js? It’s considered a bad practice. Let’s fix it.
We still need to put that url somewhere. Add data attribute to notifications placeholder element:
Then we change our modal close function once again:
And now we’re done :)
Reloading table using ajax
At this point we have a nice modal which saves the data and shows us notifications. Yet something feels missing. It would be even better if we could see new contact in a table once the data is saved.
Right now we don’t event display saved contacts. We see nothing even after we refresh our page. Firstly we need to modify
Index action method to pass contacts list to view:
Then, in order to display it, we modify the view:
It’s good time for you to test it now. Run the app, add new contact and hit F5 to refresh the page.
What we’re going to do now is to remove the need to refresh the page manually. We do this with another ajax request. It will get the rendered table. This works similary to notification (advanced version).
Since we’ll be replacing table HTML we set its
id and we add
Did you notice that I used the
html()), but instead we replace whole HTML element (
It works, but it’s glitchy. Reason for that is the
Index method, which returns whole page instead of table.
It is possible to detect wheter the request is regular or ajax. We can use this knowledge to make
Index return whole page or just the part of it (table). In case of ajax request we’ll return PartialView which will return only the table HTML.
Now it’s time I’ll show you the trick promised earlier. You can determine if request is sent via ajax by inspecting headers. Ajax requests send
X-Requested-With header with value
New partial view file consist of the table we already have in
Since this is the same table as the one in
Index.cshtml, we can remove duplicated code by reusing partial view. Let’s render
That’s all, you can now test it.
Opening modals with dynamically created buttons
At times we generate buttons dynamically. It can happen when you use some kind of front-end library or framework, maybe you create this button on your own somewhere in your front-end code. Currently our code doesn’t handle this scenario.
Reason for this is the event handler. It is attached on page load. So everything that happens after that time won’t have the click event required to open modal:
Fortunately the fix is easy. The
on() function helps to set up event handler for an area (e.g. HTML element with dynamic content).
Let’s make sure our jQuery code finds all buttons within document on click event:
Instead of finding all elements matching critera upon document ready we set up a handler for all clicks on elements inside document.
Note that using
document is suboptimal. It runs the event handler every time user clicks. Ideally you would set it up on container with dynamic elements.