Update data in block template using knockout js
-
16-04-2021 - |
Question
I'm at a dead end. I'm trying realise custom pagination on frontend page.
So, hear my code in modulename/view/frontend/web/js/blog.js
define([
'jquery',
'ko',
'uiComponent',
'domReady!'
], function (
$,
ko,
Component
) {
'use strict';
let page = 1;
let limit = 0;
let total = 0;
let numPages = 1;
let getQuery = (page) => {
let tmp = {
data: [],
limit: 0,
total: 0
};
$.ajax({
async: false,
global: false,
url: "/blog/index/get?page=" + page,
method: 'GET',
success: function (res) {
tmp.data = res.data;
tmp.page = res.page;
tmp.limit = res.limit;
tmp.total = res.total;
tmp.num_pages = res.num_pages;
}
});
return tmp;
};
let changePage = (page) => {
let btn_next = document.getElementById("btn_next");
let btn_prev = document.getElementById("btn_prev");
// Validate page
if (page < 1) {
page = 1
}
if (page > numPages) {
page = numPages;
}
if (page === 1) {
btn_prev.style.visibility = "hidden";
} else {
btn_prev.style.visibility = "visible";
}
if (page === numPages) {
btn_next.style.visibility = "hidden";
} else {
btn_next.style.visibility = "visible";
}
};
return Component.extend({
defaults: {
template: 'Magespace_Blog/blog'
},
initialize: function (config) {
this._super();
this.getPosts(config.page)
console.log(ko);
return this;
},
getDate: (value) => {
const date = new Date(value);
return date.getMonth() + ' ' + date.getDate() + ', ' + date.getFullYear();
},
getPosts(pageArg) {
let res = getQuery(pageArg);
page = res.page;
total = res.total;
limit = res.limit;
numPages = res.num_pages;
this.posts = res.data;
},
prevNextBtns: () => {
let btn_prev = document.getElementById("btn_prev");
let btn_next = document.getElementById("btn_next");
if (page < 2) {
btn_prev.style.visibility = 'hidden';
}
if (numPages === 1 || page === numPages || page > numPages) {
btn_next.style.visibility = 'hidden';
}
},
prevPage: () => {
if (page > 1) {
page--;
changePage(page);
}
},
nextPage: () => {
if (page < numPages) {
page++;
changePage(page);
}
},
});
});
modulename/view/frontend/templates/blog.phtml
<?php
/** @var Magento\Framework\View\Element\Template $block */
$page = $block->getRequest()->getParam('page') ?? 1;
$blogViewModel = $block->getData('viewModel');
?>
<div class="blog-container" data-bind="scope: 'blog'">
<!-- ko template: getTemplate() --><!-- /ko -->
</div>
<script type="text/x-magento-init">
{
"*": {
"Magento_Ui/js/core/app": {
"components": {
"blog": {
"component": "Magespace_Blog/js/blog",
"posts": [],
"total": <?= $blogViewModel->getTotalPostsCount() ?>,
"page": <?= $page ?>
}
}
}
}
}
</script>
modulename/view/frontend/web/template/blog.html
<ul>
<!-- ko foreach: { data: posts, as: 'post' } -->
<li class="post-container" data-bind="attr: {id: post.id}">
<div class="post-image"></div>
<div class="post-container__content">
<a data-bind="attr:{href: post.url}"><h2 data-bind="text: post.title"></h2></a>
<div class="post-meta">
<div class="column-1" data-bind="text: $parent.getDate(post.published_time)"></div>
<div class="column-2" data-bind="text: post.author"></div>
</div>
<p data-bind="text: post.content"></p>
</div>
</li>
<!-- /ko -->
</ul>
<div class="pagination" data-bind="afterRender: prevNextBtns()">
<a id="btn_prev" data-bind="click:prevPage">Prev</a>
<a href="#" class="active">1</a>
<a id="btn_next" data-bind="click:nextPage">Next</a>
</div>
How i can update post list in tag (modulename/view/frontend/web/template/blog.html) from uiComponent, when an ajax request occurs?
Solution
You need to set this.posts as a KO observable and then update that. At the moment you are simply updating a JS object which will not inform KO to update the frontend.
Within Component.extend
add:
posts: ko.observable(),
Rather than this.posts = res.data;
use this.posts(res.data)
This will update this.posts
with the new data, which will in turn update the frontend.
OTHER TIPS
Thanks to Ben Crook. It's working!
That's what I got.
define([
'jquery',
'ko',
'uiComponent',
'domReady!'
], function (
$,
ko,
Component
) {
'use strict';
/ ... /
return Component.extend({
defaults: {
template: 'Magespace_Blog/blog'
},
posts: ko.observable([]),
initialize: function (config) {
self = this;
this._super();
self.getPosts(config.page)
return this;
},
initObservable: function () {
this._super();
this.observe('posts');
return this;
},
/ ... /
getPosts(pageArg) {
let res = getQuery(pageArg);
page = res.page;
total = res.total;
limit = res.limit;
numPages = res.num_pages;
this.posts(res.data);
},
/ ... /
prevPage: () => {
if (page > 1) {
page--;
changePage(page);
self.getPosts(page);
}
},
nextPage: () => {
if (page < numPages) {
page++;
changePage(page);
self.getPosts(page);
}
},
});
});