Skip to content
This repository was archived by the owner on Dec 18, 2024. It is now read-only.

Commit 38d09dd

Browse files
committed
feat(news): implement data list for news comments
Implement data list with loader as a feature to load the comments of news in an reusable way. The data list can be used for all pushable data models.
1 parent 3132b03 commit 38d09dd

File tree

7 files changed

+126
-43
lines changed

7 files changed

+126
-43
lines changed

src/legendsrising.js

+12-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
11
import {load} from 'aurelia-environment';
2-
import {ViewLocator, LogManager} from 'aurelia-framework';
2+
import {ViewLocator, LogManager, DirtyCheckProperty} from 'aurelia-framework';
33
import {ConsoleAppender} from 'aurelia-logging-console';
44
import authConfig from './configuration/auth-config';
55

6+
/** DEBUG DIRTY CHECKING **/
7+
const logger = LogManager.getLogger('my-app');
8+
DirtyCheckProperty.prototype.standardSubscribe = DirtyCheckProperty.prototype.subscribe;
9+
DirtyCheckProperty.prototype.subscribe = function(context, callable) {
10+
this.standardSubscribe(context, callable);
11+
logger.warn(`'${this.obj.constructor.name}.${this.propertyName}' is being dirty checked`, this.obj);
12+
};
13+
/** /DEBUG DIRTY CHECKING **/
14+
615
ViewLocator.prototype.convertOriginToViewUrl = function(origin) {
716
let moduleId = origin.moduleId;
817
let id = (moduleId.endsWith('.js') || moduleId.endsWith('.ts')) ? moduleId.substring(0, moduleId.length - 3) : moduleId;
@@ -35,7 +44,8 @@ export function configure(aurelia) {
3544
settings.containerSelector = '#notification-container';
3645
settings.timeout = 10000;
3746
})
38-
.feature('resources/features/navigation');
47+
.feature('resources/features/navigation')
48+
.feature('resources/features/data-list');
3949

4050
aurelia.start()
4151
.then(a => a.setRoot('app', document.body))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export class DataListController {
2+
constructor(dataCollector) {
3+
this.dataCollector = dataCollector;
4+
}
5+
6+
fetchData(page) {
7+
return this.dataCollector(page);
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import {BindingEngine, bindable, bindingMode, customElement, containerless, inject, inlineView} from 'aurelia-framework';
2+
3+
@containerless
4+
@customElement('data-list')
5+
@inlineView(`
6+
<template>
7+
<slot></slot>
8+
</template>
9+
`)
10+
@inject(BindingEngine)
11+
export class DataListElement {
12+
@bindable({defaultBindingMode: bindingMode.twoWay}) data = [];
13+
@bindable({defaultBindingMode: bindingMode.twoWay}) model;
14+
@bindable controller;
15+
16+
bindingEngine;
17+
pageObserver;
18+
19+
constructor(bindingEngine) {
20+
this.bindingEngine = bindingEngine;
21+
}
22+
23+
attached() {
24+
this.data = [];
25+
this.model = {loading: true, currentPage: 1, lastPage: 1, totalPages: 1};
26+
this.pageObserver = this.bindingEngine.propertyObserver(this.model, 'currentPage').subscribe(this.pageChanged.bind(this));
27+
this._process();
28+
}
29+
30+
detached() {
31+
this.pageObserver.dispose();
32+
}
33+
34+
pageChanged() {
35+
this._process();
36+
}
37+
38+
_process() {
39+
this.model.loading = true;
40+
Promise
41+
.resolve(this.controller.fetchData(this.model.currentPage))
42+
.then(comments => {
43+
this.data = this.data.concat(comments.data);
44+
this.model.total = comments.total;
45+
this.model.lastPage = comments.last_page;
46+
this.model.loading = false;
47+
});
48+
}
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import {customElement, containerless, bindable, bindingMode, inlineView} from 'aurelia-framework';
2+
3+
@containerless
4+
@customElement('data-loader')
5+
@inlineView(`
6+
<template>
7+
<template replaceable part="item-template">
8+
<a href="#" click.delegate="nextPage()">Next</a>
9+
</template>
10+
</template>
11+
`)
12+
export class DataLoaderElement {
13+
@bindable({defaultBindingMode: bindingMode.twoWay}) dataListModel;
14+
15+
nextPage() {
16+
this.dataListModel.currentPage++;
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export * from './controller';
2+
3+
export function configure(config) {
4+
config.globalResources([
5+
'./data-list', './data-loader'
6+
]);
7+
}

src/view-models/news/view.js

+6-26
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
import {inject} from 'aurelia-framework';
22
import {AuthService} from 'aurelia-authentication';
33
import {NotificationService} from 'aurelia-notify';
4+
import {DataListController} from 'resources/features/data-list/controller';
45
import {NewsService} from '../../services/news/news-service';
56
import {NewsCommentsService} from '../../services/news/news-comments-service';
67

78
const ENTER_KEY = 13;
89

910
@inject(NewsService, NewsCommentsService, AuthService, NotificationService)
1011
export class View {
11-
loading = false;
12-
1312
constructor(newsService, newsCommentsService, authService, notificationService) {
1413
this.newsService = newsService;
1514
this.newsCommentsService = newsCommentsService;
1615
this.authService = authService;
1716
this.notificationService = notificationService;
17+
18+
this.dataListController = new DataListController(options => this.loadMore(options));
1819
}
1920

2021
activate(params, routeConfig) {
@@ -28,16 +29,6 @@ export class View {
2829
this.user = null;
2930
});
3031

31-
let commentsPromise = this.newsCommentsService.getAll(params.id)
32-
.then(comments => {
33-
this.comments = comments.data;
34-
this.currentPage = comments.current_page;
35-
this.lastPage = comments.last_page;
36-
})
37-
.catch(() => {
38-
this.comments = [];
39-
});
40-
4132
let newsPromise = this.newsService.get(params.id)
4233
.then(news => {
4334
this.news = news;
@@ -47,7 +38,7 @@ export class View {
4738
this.news = null;
4839
});
4940

50-
return Promise.all([userPromise, commentsPromise, newsPromise]);
41+
return Promise.all([userPromise, newsPromise]);
5142
}
5243

5344
onKeyUp(event) {
@@ -78,19 +69,8 @@ export class View {
7869
});
7970
}
8071

81-
loadMore() {
82-
this.loading = true;
83-
this.newsCommentsService.getAll(this.newsId, this.currentPage + 1)
84-
.then(comments => {
85-
this.comments = this.comments.concat(comments.data);
86-
this.currentPage = comments.current_page;
87-
this.lastPage = comments.last_page;
88-
this.loading = false;
89-
})
90-
.catch(() => {
91-
this.comments = [];
92-
this.loading = false;
93-
});
72+
loadMore(page) {
73+
return this.newsCommentsService.getAll(this.newsId, page);
9474
}
9575

9676
get isAuthenticated() {

src/views/news/view.html

+25-15
Original file line numberDiff line numberDiff line change
@@ -23,33 +23,43 @@ <h4><a href="#/news/view/${news.id}">${news.title}</a></h4>
2323
<div class="card-text">${news.text}</div>
2424
</div>
2525

26-
<div class="card-footer aurelia-animators" if.bind="isAuthenticated || comments.length > 0">
26+
<div class="card-footer aurelia-animators">
2727
<div class="news-card-comment" if.bind="isAuthenticated">
2828
<a href="#/profiles/view/${user.id}" class="pull-left">
2929
<!-- Todo: image path -->
3030
<img alt="${user.username}" src="http://lr.local/img/avatar/${user.avatar}">
3131
</a>
3232

3333
<div class="media-body">
34-
<input class="form-control" placeholder="Write comment..." autofocus keyup.delegate="onKeyUp($event)" value.bind="comment">
34+
<input class="form-control" placeholder="Write comment..." autofocus keyup.delegate="onKeyUp($event)"
35+
value.bind="comment">
3536
</div>
3637
</div>
3738

38-
<div class="news-card-comment au-animate" repeat.for="item of comments">
39-
<a href="#/profiles/view/${item.user.id}" class="pull-left">
40-
<!-- Todo -->
41-
<img alt="${item.user.username}" src="http://lr.local/img/avatar/${item.user.avatar}">
42-
</a>
43-
<div class="media-body">
44-
<a href="#/profiles/view/${item.user.id}">${item.user.username}</a> ${item.text}
45-
<br>
46-
<small class="text-muted">${item.created_at}</small>
39+
<data-list controller.bind="dataListController" data.bind="data" model.bind="model">
40+
<div class="news-card-comment au-animate" repeat.for="item of data">
41+
<a href="#/profiles/view/${item.user.id}" class="pull-left">
42+
<!-- Todo -->
43+
<img alt="${item.user.username}" src="http://lr.local/img/avatar/${item.user.avatar}">
44+
</a>
45+
<div class="media-body">
46+
<a href="#/profiles/view/${item.user.id}">${item.user.username}</a> ${item.text}
47+
<br>
48+
<small class="text-muted">${item.created_at}</small>
49+
</div>
4750
</div>
48-
</div>
4951

50-
<div class="news-card-comment">
51-
<a href="#" click.delegate="loadMore()">Load more comments</a> <i class="fa fa-fw fa-spinner fa-spin ${loading ? '' : 'invisible'}"></i>
52-
</div>
52+
<data-loader data-list-model.bind="model">
53+
<template replace-part="item-template">
54+
<div class="news-card-comment ${dataListModel.lastPage > 1 || dataListModel.loading ? '' : 'hidden-xl-down'}">
55+
<a href="#" click.delegate="nextPage()" class="${dataListModel.currentPage != dataListModel.lastPage ? '' : 'hidden-xl-down'}">
56+
Load more comments
57+
</a>
58+
<i class="fa fa-fw fa-spinner fa-spin ${dataListModel.loading ? '' : 'hidden-xl-down'}"></i>
59+
</div>
60+
</template>
61+
</data-loader>
62+
</data-list>
5363

5464
<div class="news-card-comment" if.bind="isAuthenticated">
5565
<a href="">Comment...</a>

0 commit comments

Comments
 (0)