Using ajax to load html vs json

jquery
#1

I have read in many places that it is best practice to use ajax to retrieve JSON and not HTML.

I understand that the reasoning behind it is it being slightly faster, and having the option to do more with the raw data rather than retrieving html.

But i haven’t been able to find good examples that explain clearly how to actually convert the JSON data in to the desired HTML output.

For example, i have a like button:

<form action="/reactions/save" method="POST">
    <button type="submit">
        <i class="fa fa-thumbs-o-up" aria-hidden="true"></i> 3
    </button>
</form>

What this shows is a thumbs up icon, and the amount of likes the item already has (which is 3 in this example).

What i want to achieve is to click on that button, to load the url /reactions/save with ajax, which saves the new like, and then to change the button to indicate that this item has been liked, and to change the amount of likes next to the button.
Basically the same as facebook, or any other website has a like button, the same as this site has a like button.

What i would normally do is attach that button to a jquery function that will load that url when clicking on it, the url would return the new button already formatted (it would return HTML), and i would use jquery to just replace the two buttons.

But as i read and am constantly told, it is better to retrieve JSON and to format that data in to the button.

I just don’t understand how, and if it would not be much simpler to just get the HTML from the response and output it rather than getting the JSON data, formatting it, and then outputting it.

General Technique for Dynamic Navigation
#2

Use JSON, that is really better.

Developer should use any oportunity to reduce dependencies between application parts. HTML in response - is very strong dependency, and that is not good.

Example: you have a lot of usecases that need actual likes’ number. If you use JSON, you can create just single server script that produces it. But if you use HTML in response… It could be impossible, because of different HTML format in any usecase.

1 Like
#3

But how would i actually update the button then?
If i’m getting the data back in JSON, how do i convert that data into the actual like button?

#4

E.g., create this button with “display: none” in your loaded site, than config it with resonded JSON, show new button an hide old element.

#5

so i would have to have a javascript function that would find that hidden button, change its contents, hide the old one and show the new one?

#6

Yes. As I anderstand, you would to send AJAX request by form submit. So in submit handler you should also to modify this button.

#7

Then that means that for every element or html that i want to reload i will have to have a function that will convert JSON in to the correct html?

Seems like a lot of work and functions.

What about if i have a whole list of items, for example, i have a button that loads a list of posts, how could i create the actual html output for this?

#8

From where do you get HTML on server? So or so you should have some HTML template. And clear, if you have a lot of similar elements, you can create just one exemplar and clone it by

element.cloneNode(true)
#9

I have all of my html file in a views folder, the html files use data that is passed to them like so: $this->data['amount_of_like'].

I’m really not sure i understand exactly how to implement this.
If there was a way to load the html file, and to pass the JSON data to it then that would sound simpler, but then that would probably be the same as just getting HTML from ajax.

How does this site use its like buttons for example? I don’t see a hidden element for the like button, all i see is that the element either gets replaced or it gets updated.

#10

You only need minimal DOM modifications really; assuming you get a JSON response like

{ "likes": 42 }`

… then with the following markup (note the data attribute):

<form action="/reactions/save" method="POST" id="like-form">
  <button type="submit" data-likes="3">
      <i class="fa fa-thumbs-o-up" aria-hidden="true"></i>
  </button>
</form>

… you can display the number of likes using CSS:

[data-likes]::after {
  content: ' ' attr(data-likes);
}

Then in the JS, instead of replacing the submit button entirely you just update its data attribute, and toggle a class that changes the icon (although it would make sense to also disable the button while waiting for the response):

document
  .getElementById('like-form')
  .addEventListener('submit', event => {
    const form = event.target
    const button = form.querySelector('button')

    event.preventDefault()
    button.disabled = true

    fetch(form.action)
      .then(response => response.json())
      .then(({ likes }) => {
        // Modify the DOM to reflect the data here
        button.dataset.likes = likes
        button.classList.toggle('active')
      })
      .catch(console.error)
      .finally(() => {
        button.disabled = false
      })
  })
#11

You should be using a database instead of JSON for this. You should have at least one table for the users and a table for items, such as posts, to be liked. You can also have a “like” table that lists the users that have liked something. Then when a like button is pushed a record is added to the “like” table with a foreign key of the item being liked. Then the total number of likes can be updated with the number of “like” records for the item. Then the button can be disabled or the text can be changed to something like “unlike”. If it is changed to “unlike” then you need to have logic to unlike the item.

#12

Thanks, but that actually was not my question at all.

I already have a system set up for posts and likes, its all working as it should, i am implementing ajax.

And based on what most people say, and m3g4p0p`s example, it seems the best way is to return JSON and to update each element separately.

But even with m3g4p0p`s example, it seems much more complex to create a javascript function for each type of element i want to update with ajax.

If i had a button that would load a list of posts through ajax, i would have to have a javascript function that would put all of the JSON data in to the actual html elements, and create the whole list like that?
And where would i even get the html from if you shouldnt be loading html through ajax?

Its all just very unclear to me and seems like it means creating a lot of javascript functions for each type of element i want to update

#13

Just returning the markup from the backend may seem easier at first, but is certainly more trouble in the long run as you have to maintain the markup (or fragments of markup) in multiple places; and as @igor_g already mentioned, each time you want to request that data elsewhere you have to create a whole new endpoint as you can’t just send the same data. And no way can you query any meaningful data from another application.

Another problem is that by destroying the original elements, you’ll lose all previously added event listeners – or worse, you still have references to those elements which keep them from getting garbage collected, thus creating memory leaks. By reusing the same elements you don’t have to worry about voiding references or reapplying event listeners (which is obviously more economical performance-wise as well).

I’m not quite sure what you mean… it depends on the complexity of course, but in my above snippet that was just 1 function with 2 lines which would otherwise have been a function with 1 line assigning the markup. Okay bad example, this is indeed twice as much. :-D Anyway with your approach OTOH you have to extend the backend for each new type of element (and probably bloat the API), so I don’t really see an advantage in that.

If everything fails you can still create markup from the data using JS, just as you would in the backend;
the probably cleanest way would be using a template right from the initial HTML though, e.g.

<template id="button-template">
  <button>You liked this!</button>
</template>
const buttonTemplate = document.getElementById('button-template')
const likeForm = document.getElementById('like-form')

// Then at some point...
likeForm.innerHTML = buttonTemplate.innerHTML

// Or:
const button = likeForm.querySelector('button')
button.replaceWith(buttonTemplate.content)

This way you still have all the markup in one place, but again you have to be careful with memory leaks of course; e.g. if button above was still being referenced elsewhere.

1 Like
#14

What i mean is that from what i understand, the best way to work with ajax is to get a JSON response, and then to use another javascript function to implement or inject that JSON response in to html.
What i understand from this is that if i have a site that has a lot of different ajax requests, then that means that i need to have a dedicated function for each type of element that i want to updated, for example:

  1. a js function for a post list
  2. a js function for a like button
  3. a js function for a menu
  4. etc …

Thats what i am understanding from everything, that when you get a JSON response from ajax, you need to “Convert” it to the correct html representation you want. Which to me means that you need a function for every type of html element you want to reload with ajax (a post element, a post list element, a like button, etc., one function for each of those types).

Maybe i’m just not understanding, it does seem like we are speaking two different languages :sweat_smile: .

The way i structured my files is that if i have a file with html that i want to reload with ajax, i save it in a separate file and folder, so for example it would be: renders/like_button.php.
This file would be included anywhere i want to show the like button, and if i want to use it in ajax, i just get the file with the ajax request, and replace the existing button with it.
So i dont have any extra html file for ajax, i use the same ones i use with regular loading.

#15

Can you provide pointers to more formal / detailed instruction regarding this technique in general?

The problem is, I’m not convinced that transmitting only JSON and then using JS to update the DOM is truly better. I think people might be overestimating the benefit of separating the data from it’s presentation. Yes, clearly there are advantages. You are pushing the presentation to where the data is presented - on the client. This gets you closer to a real MVC relation because you can then just update the “model” in the form of a JSON update on the client and the “view” updates in reaction to those changes. But unfortunately the current HTML, JavaScript, CSS tool-chain does not provide the necessary functionality to effectively implement that. Even a client-side template system that could transparently bind fields within the view to data such that it reacts to changes in the data would not be enough because there are instances where the dom changes radically adding new elements to a lists and trees of elements. It may not be possible or practical to pre-load templates of content in advance. The content could easily be highly varied or even totally unique.

Also, I don’t see why performance would necessarily be better because you are doing a lot of work in the beginning. You must generate every possible fragment of HTML that will be used by the page up-front (and those fragments may not even be used). Initially the client will need to parse a lot more JS. And any performance benefits will be limited to the server. The client will obviously not be more efficient since now it’s handling quite a lot of dynamic updates to the DOM which must be re-interpreted by the browser to change the view.

The idea of separating the data from it’s representation is great but in practice, each operation may only need a small fraction of data in the form of JSON. Meaning if you have a generic JSON service and the client only wants to know how many “likes” someone has, what sort of database code is being invoked to get that? Is it more than necessary?

You mention dependencies but consider the dependencies of this client-side-JSON-update method. If you make a change, you might have to update the pre-loaded HTML “template”, the JSON data, then the extra JS used to manipulate the DOM and the extra CSS ‘content’ trickery used to update the “template”. Alternatively, if you just emit a fragment of HTML and attach it to the DOM, you’re just changing the server side template (which is a real template like PHP for example so it’s a LOT easier to use) and some relatively simple JS and possibly no JS at all if the operation of the generic variety that just is inserted into a div or replaces some div.

It’s also harder to do things on the client. The server can have sophisticated libraries that are not present on the client. And yet this method effectively pushes a lot of work to the client. So any decision making that goes into rendering is limited to what can be done in JS.

So who else is advocating this method? Where did you get this idea from? Is there a good “tutorial” online somewhere or some forum posts that describes the technique in more detail? I’m not just going to follow-the-pack. I would have to understand this a lot better to make the leap.

#16

Example. Mail box that sends every minute AJAX request to server and shows actual messages. Let this service has a million users, and any user at start of his work opens mail box site and time to time checks for new messages.

  1. HTML in response. Million requests pro minute. For any request server schould not only pull data from DB, but also render HTML-view. How much resources needs server for it? 20% or 50% more? I don’t know.

Another question: how bigger will be traffic server-client? In five times or in ten times?

  1. JSON in Response. Yes, client needs some tr or li element as template for messages list building, and what if site completelly loaded in average one or two times pro day? Client needs more time to refresh mail box contents? Okey five milliseconds more. I think, user survives it.
#17

Ah okay fair enough. The main issue remains that the backend has to provide an endpoint for every possible element, rather than just serving the data and letting the frontend decide what to do with it.

Hi there @ioplex, well coupling the data with the presentation just doesn’t scale well. Whenever the frontend needs some ever so minor adjustments, someone has to go to the backend team and tell them they need an additional class, or an additional endpoint that serves a slightly different markup. That not only slows down the development process but also gets harder and harder to maintain.

You can still build the markup from scratch, if by setting the innerHTML – I don’t see how this differs from assembling the markup on the server side, only that JS also has less crude means to update the DOM (if indeed applicable). And speaking of template engines, some even have implementations for both JS and (other) server side languages… e.g. pug OTTOMH.

No you don’t have to, you can also lazy load them when needed. With bundlers like webpack you can even directly import HTML into the JS, for example

import('./my-template.html').then(html => {
  myElement.innerHTML = html
})

This is admittedly a rather advanced topic, but you’ve been mentioning the frontend toolchain. :-P Anyway this way you only load the template once when needed, and reuse it when requesting more data (it’s simply getting cached by the browser); and the JSON data alone clearly takes less time to travel the internet.

PHP is just a language like JS, it’s not a template. Both have their ways to interpolate strings, and there’s no shortage of template engines for both.

Separation of concerns and loose coupling, for example.

(x-post)