This is the voa Special English Health Report. I’m Steve Jobs. I’m Steve Jobs
Introduction to the
Show a simple Angular data flow management solution using the Todo List example. As shown in figure:
The project structure is shown as follows:
Our purpose is simple:
- Generate a number of
TODO item
; - Show the
TODO item
; - Modify the
TODO item
, so that its data can be synchronized without the need for data re-request;
data-flow.componnet.ts & data-flow.service.ts
Starting with the outermost component, we will have a Container as an entry point and a Service as its data management layer
- data-flow.service.ts
.@Injectable({
providedIn: 'root'
})
export class DataFlowService {
dataFlowSubject: BehaviorSubject<DataFlowData>;
dataFolwData: DataFlowData;
constructor() {
if (!this.dataFolwData) {
this.dataFolwData = this.initDataFlowData();
this.mockList(10);
}
this.dataFlowSubject = new BehaviorSubject<DataFlowData>(this.dataFolwData);
}
getDataFlowSubject = (a)= > {
this.updateData();
return this.dataFlowSubject;
}
initDataFlowData = (a)= > ({
list: []
});
updateData = (a)= > {
this.dataFlowSubject.next(this.dataFolwData);
}
mockList = (num: number) = > {
const list: TodoList[] = [];
if (num > 0) {
for (let i = 0; i < num; i++) {
list.push({
id: cuid(),
text: `todo-${i}`, status: TodoStatus.TODO }); }}this.dataFolwData.list = list; }... }Copy the code
- data-flow.componnet.ts
@Component({
selector: 'data-flow',
templateUrl: './data-flow.component.html',
styleUrls: ['./data-flow.component.scss']})export class DataFlowComponent implements OnInit {
dataFlowSubject: BehaviorSubject<DataFlowData>;
todoList: TodoList[];
constructor(
private dataFlowService: DataFlowService
) {
this.dataFlowSubject = this.dataFlowService.getDataFlowSubject();
}
ngOnInit() {
this.dataFlowSubject.subscribe((data: DataFlowData) = > {
this.todoList = data.list; }); }}Copy the code
We registered the Service as a singleton that existed when the app was generated. We initialized the data, mock the data, generated a BehaviorSubject subscripter with rxJS, and then put the initialization data into the generated subscripter as the initial data.
The component gets the service’s subscriber when it constructs the Component, subscribes to our update method in the component’s initialized hook function, and the Component connects to the Service.
Here it is not hard to see, we have stored in the service of a persistent data, which is our total a data, just behind us will modify the data, and then to redraw updating components, although the data here is the mock false data, but in the real project, we can take back data exist here, Then do the operation of adding, deleting, changing and checking it, which can avoid some unnecessary network consumption, but there will also be some disadvantages, that is, the amount of data can not be recommended too large;
So what we’re going TODO is add TODO,
- data-flow.service.ts
add = (item: TodoList) = > {
this.dataFolwData.list.push(item);
this.updateData();
}
Copy the code
- data-flow.componnet.ts
addTodo = (a)= > {
if (this.addText) {
this.dataFlowService.add({
id: cuid(),
text: this.addText,
status: TodoStatus.TODO
});
this.addText = ' '; }}Copy the code
Since we used updateData in the add of the service to trigger the subscriber’s next, passing out the latest data, the Component receives the data and redraws from it;
Similarly, we could write a delete method, which also calls updateData to trigger the subscriber to update the data,
- todo-item.component.ts
@Component({
selector: 'todo-item',
templateUrl: './todo-item.component.html',
styleUrls: ['./todo-item.component.scss']})export class TodoItemComponent implements OnInit {
@Input() todoItem: TodoList;
constructor(
private dtService: DataFlowService
) {
}
ngOnInit() {}
deleteItem = (a)= > {
this.dtService.deleteItem(this.todoId); }}Copy the code
- data-flow.service.ts
deleteItem = (id: string) = > {
this.dataFolwData.list = this.dataFolwData.list.filter((item: TodoList) = >item.id ! == id);this.updateData();
}
Copy the code
Relationship between Detail.componentand data-flow.service
To verify that the data of the data-flow service is persistent and reusable, create a component detail Container to display the detail data and the data that can be changed, and then synchronize the data to the data-flow service. Go back to the data-flow container and check whether our changes have taken effect.
- detail.component
@Component({
selector: 'item-detail',
templateUrl: './item-detail.component.html',
styleUrls: ['./item-detail.component.scss']})export class TodoDetailComponent implements OnInit {
detailSubject$: DetailServiceSubject;
detailId: string;
detail: TodoList;
isLoading: boolean;
todoStatus = TodoStatus;
constructor(
private route: ActivatedRoute,
private router: Router,
private detailService: DetailService,
private dataFlowService: DataFlowService
) {
this.detailSubject$ = this.detailService.getDetailSubject();
this.detailSubject$.subscribe(this.updateDetail);
}
ngOnInit() {
const newId = this.route.snapshot.paramMap.get('id');
this.isLoading = true;
if (newId === this.detailId) {
this.isLoading = false;
} else {
this.detailId = newId;
this.detailService.getDetail(this.detailId); }}get status() {
return statusMapping[this.detail.status] || 'stateless';
}
updateDetail = (data: TodoList) = > {
this.detail = data;
this.isLoading = false;
}
changeValue = (event: Event) = > {
const value = (event.target as HTMLInputElement).value;
this.detail.text = value;
}
delete = (a)= > {
this.dataFlowService.delete(this.detailId);
this.router.navigate(['/todolist-demo']);
}
change = (a)= > {
this.dataFlowService.updateItem(this.detail);
this.router.navigate(['/todolist-demo']);
}
changeStatus = (event: Event) = > {
const value = (event.target as HTMLInputElement).value;
this.detail.status = value asTodoStatus; }}Copy the code
- detail.service
@Injectable({
providedIn: 'root'
})
export class DetailService {
detailSubject: DetailServiceSubject;
detailData: TodoList;
constructor(
private dataFlowService: DataFlowService
) {
this.detailData = null;
this.detailSubject = new BehaviorSubject<TodoList>(this.detailData);
}
getDetailSubject = (a)= > {
this.updateData();
return this.detailSubject;
};
getDetail = (id: string) = > {
if (get(this.detailData, 'id'.null) === id) {
this.updateData();
} else {
this.dataFlowService.asyncGetItemById(id, (data: TodoList) = > {
this.detailData = data;
this.updateData(); })}}; updateData =(a)= > {
this.detailSubject.next(this.detailData); }}Copy the code
- data-flow.service.ts
updateItem = (item: TodoList) = > {
this.dataFolwData.list = this.dataFolwData.list.map(todo= > {
if (todo.id === item.id) return item;
return todo;
})
}
asyncGetItemById = (id: string, callback) = > {
const detail = this.dataFolwData.list.filter(item= > item.id === id)[0];
setTimeout(function() { callback(detail) }, 1000);
};
changeStatus = (item: TodoList) = > {
this.dataFolwData.list = this.dataFolwData.list.map((d: TodoList) = > {
if (d.id === item.id) {
return item;
}
return d;
});
this.updateData();
}
Copy the code
Similarly, the Component at the Container level processes and updates data in services, and the detail Component subscribes and updates data in the same way.
In the detail Component, the dataFlowService is declared to synchronize data changes to the list page data. This way, the data will be changed only when the page is returned to the previous page. Of course, it only synchronizes necessary data, such as state text deletion. If you have other data that is only specific to the detail, but not owned by the list, you don’t need to synchronize;
The effect is as follows:
When entering the detail page, there is a loading prompt, which is a fake asynchronous fetch code. In the detail component, there is a judgment to request data if the current ID is different from the previous ID. This is because a BehaviorSubject is used to construct this component. During the subscription, the BehaviorSubject sends the last number of times as data. Therefore, when the id is the same in the detail Component, There is no need to fetch data, which reduces network requests and increases the user experience.
conclusion
Data management is carried out through Service, and the data update method is subscribed in Component to obtain (new) data for page update, thus reducing network requests and improving user experience. In addition, a clearer data flow can be achieved, and it is easy to understand the data flow to understand the business process.
The resources
- rxjs-BehaviorSubject
- angular-service