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 $.post
and serialize()
jQuery methods, which won’t work with files (learn why here).
The 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.
|
|
As stated above $.post
won’t work, so replace it with $.ajax
call:
|
|
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.
Add following div
to your layout:
|
|
Next step is to insert message there. We’ll need to modify our JavaScript method responsible for closing modal on success. Let’s remind ourselves how this piece of code looks like:
|
|
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.
Also, if you want to you can also use HTML here, you only have to replace text()
with html()
:
|
|
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.
|
|
Contact action returns PartialView. How/where can we store our message? The best way is the TempData dictionary. It’s like Session, but whatever is stored there disappears after you read it.
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:
|
|
Great. Now what? Well, we need to let our JavaScript code fetch these notifications somehow. Since we want to do that using ajax request, the best way would be to create another action. This new action would return all notifications. It’s rather simple, so there is nothing new to explain here:
|
|
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:
|
|
Next thing to do is to get those notifications once we close modal window. We need to modify our JavaScript code with new ajax request:
|
|
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 data-url
:
|
|
Did you notice that I used the Index
action? Currently it returns whole page (much more than just the table). I’ll show you neat trick in a moment, but before we get to that let’s see the modifications for our JavaScript code. It looks very much like the notification code. The difference here is that we do not insert HTML into placeholder (html()
), but instead we replace whole HTML element (replaceWith()
):
|
|
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 XMLHttpRequest
:
|
|
New partial view file consist of the table we already have in Index.cshtml
:
|
|
Since this is the same table as the one in Index.cshtml
, we can remove duplicated code by reusing partial view. Let’s render _Table.cshtml
inside Index.cshtml
:
|
|
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 on()
on document
is suboptimal. It runs the event handler every time user clicks. Ideally you would set it up on container with dynamic elements.