I’v been searching for hours now and didn’t find anything close to my use case.
- I have a classic / multi page / server rendered e-commerce webstie made with JAVA
- I have a page where the server renders a list of products with a pagination
- Today, i use jQuery to do the pagination to give a better loading experience to the user
- On my server, if the request is AJAX a send a json response, else i render a normal html view
- With jQuery and vanilla it’s really easy, with Vue it doesn’t seem to work because Vue’s v-for and other template binding replaces the server rendered template directly…
- The server would render this :
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
article {
margin: 8px 0;
background: #eee;
padding: 20px;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
del {
color: rgba(0, 0, 0, 0.3);
}
<!-- server rendered -->
<div id="app">
<h2>Freelance list</h2>
<article>
<h3>louane</h3>
<p>
City : <strong>courbevoie</strong>
<br> Phone : <strong>05-36-23-51-89</strong>
</p>
</article>
<article>
<h3>indra</h3>
<p>
City : <strong>rheden</strong>
<br> Phone : <strong>(354)-415-2419</strong>
</p>
</article>
<article>
<h3>angelo</h3>
<p>
City : <strong>montpreveyres</strong>
<br> Phone : <strong>(883)-474-9314</strong>
</p>
</article>
<a href="/prev-link">prev</a>
<a href="/next-link">next</a>
</div>
<!-- server rendered -->
- I want to be able to do something like this but with Vue :
// fake url link, normally this would be taken from the href or something
var url = 'https://randomuser.me/api/?seed=abc&results=3&page=';
var page = 1;
var $articles = $('.articles');
var tpl = $articles.children().eq(0).clone();
$('.prev').click(function(e) {
e.preventDefault();
if (page <= 1) {
return
}
page--;
$.getJSON(url + page)
.done(onReqDone);
});
$('.next').click(function(e) {
e.preventDefault();
page++;
$.getJSON(url + page)
.done(onReqDone);
});
function onReqDone(res) {
$articles.html('');
res.results.forEach(function(user) {
var $node = tpl.clone();
$node.find('h3').text(user.name.first);
$node.find('strong:eq(0)').text(user.location.city);
$node.find('strong:eq(1)').text(user.phone);
$articles.append($node);
window.scroll(0, 0);
});
}
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
article {
margin: 8px 0;
background: #eee;
padding: 20px;
}
h2 {
font-weight: bold;
margin-bottom: 15px;
}
del {
color: rgba(0, 0, 0, 0.3);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- server rendered -->
<div id="app">
<h2>Freelance list</h2>
<div class="articles">
<article>
<h3>louane</h3>
<p>
City : <strong>courbevoie</strong>
<br> Phone : <strong>05-36-23-51-89</strong>
</p>
</article>
<article>
<h3>indra</h3>
<p>
City : <strong>rheden</strong>
<br> Phone : <strong>(354)-415-2419</strong>
</p>
</article>
<article>
<h3>angelo</h3>
<p>
City : <strong>montpreveyres</strong>
<br> Phone : <strong>(883)-474-9314</strong>
</p>
</article>
</div>
<a href="/prev-link" class="prev">prev</a>
<a href="/next-link" class="next">next</a>
</div>
<!-- server rendered -->
Any ideo on how to do it ? Here are my tries :
https://jsfiddle.net/7270zft3/2/ : problem, it doesn’t remove the old dom
PS :
Before anyone talks about SSR with Vue ou just doing an SPA, here’s why i cant :
- This e-commerce website can’t be totally re made with a Single Page App, it will cost too much time and money for the benefit it would bring to us
- This e-commerce needs SEO to continue to drive traffic, just like any e-commerce btw
- If Vue can really be used like jQuery (this is why we bet on Vue), we should be able to do this without doing a full rewrite
- Event if we had time to rewrite an SPA, we can’t use SSR because our backend is made with JAVA and SSR seems to only be available with node and PHP with v8js module
3
Answers
Someone on the Vue forum found a good approach close to what was posted here but suited better my need : https://forum.vuejs.org/t/using-vue-to-enhance-existing-multi-page-server-rendered-classic-web-app/30934/20
You can attach a DOM ref to the server rendered content and then just as in jQuery, just clear the contents to the DOM element.
You need to perform this action only once, so you can may be add checks to see if your DOM ref is empty if
page === 1
But to do it Vue style, it is advised that you remove the rendering of first page from the server and let Vue handle data-fetching by itself so that Vue can use the
data
it stores as the source of truth instead of manipulating the DOM.An example of hydration. I wasn’t able to get Vue to stop warning me that my generated HTML didn’t match the original; it’s not critical. In development, Vue will “bail and do a full render”, but in production it will leave the pre-rendered. You just want to be sure they match, so that when it does update, it’s what you expect.
I left jQuery in for the
getJSON
. Other than that, it’s jQuery free.