【问题标题】:Template show <object Object> but no error in observable async pipe模板显示 <object Object> 但可观察异步管道中没有错误
【发布时间】:2020-05-18 02:59:00
【问题描述】:

我有可观察到的待办事项(id、标题、完整)

TodosCompenent/index.ts

import {Component, OnInit, ChangeDetectionStrategy, ChangeDetectorRef} from '@angular/core';
import {Todo, ITodo} from '../../../todo/todo';
import {TodoDataService} from '../../Services/API/todo-data.service';
import {APIService} from '../../Services/API/APIServices';
import {AuthService} from '../../Services/AuthService/auth.service';
import {Router} from '@angular/router';
import {Observable} from 'rxjs';
import {select, Store} from '@ngrx/store';
import {TodoState} from '../../store/Reducer/todo.reducers';
import {getTodos} from '../../store/selector/todo.selector';
import {getTodoRequest} from '../../store/Actions/todo.action';

@Component({
  selector: 'app-todos',
  templateUrl: './index.html',
  styleUrls: ['./index.css'],
  providers: [TodoDataService, APIService],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TodosComponent implements OnInit {


 constructor(private todoDataService: TodoDataService,
             private auth: AuthService,
             private route: Router,
             private ref: ChangeDetectorRef,
             private store: Store<TodoState>
  ) {}
  todo$ = this.store.pipe(select(getTodos));
  public ngOnInit() {
   // this.store.dispatch(getTodoRequest());
  }
  onAddToDo(todo) {
    // this.todoDataService.addTodo(todo).subscribe((newTodo) => {
    //   this.todos = this.todos.concat(newTodo);
    //   // this.fetchTodo();
    // });
  }
  // onToggleTodoComplete(todo) {
  //   this.todoDataService.onToggleComplete(todo).subscribe((updatedTodo) => {
  //     todo = updatedTodo;
  //     // this.fetchTodo();
  //   });
  // }
  // onRemoveTodo(todo) {
  //   this.todoDataService.deleteTodo(todo.id).subscribe((_) => {
  //     this.todos.filter((t) => t.id !== todo.id);
  //     // this.fetchTodo();
  //   });
  // }
  // fetchTodo() {
  //   this.todoDataService.getTodos().subscribe((todos) => {
  //     this.todos = todos;
  //   });
  // }
  signOut() {
    this.auth.signOut();
    this.route.navigate(['/index']);
  }

}

这个是使用异步管道但不工作仍然在模板中显示 [object Object]

<app-todo-list _ngcontent-adf-c193="" _nghost-adf-c190="" ng-reflect-todos="[object Object]"><div _ngcontent-adf-c190="" class="view ng-star-inserted"> No Todo at the moment </div>
</app-todo-list>

存储中的数据

{
  todo: [
    {
      id: 1,
      title: 'stay home',
      complete: true
    },
    {
      title: 'test',
      complete: true,
      id: 2
    },
    {
      title: 'demo',
      complete: true,
      id: 3
    }
  ],
  type: 'GET_TODO_SUCCESS'
}

TodosCompenent/index.html

  <app-todo-list-header (add)="onAddToDo($event)"></app-todo-list-header>
  <div *ngIf="(todo$ | async) as todos">
  <app-todo-list
    [todos]="todos"
    (toggleComplete)="onToggleTodoComplete($event)"
    (remove)="onRemoveTodo($event)"
  ></app-todo-list>
  <app-todo-list-footer [todos]="todo$ | async"></app-todo-list-footer>
  <div fxLayoutAlign="center center" >
    <button mat-flat-button color="primary" (click)="signOut()">Logout</button>
  </div>
  </div>
</section>

我使用应用状态来选择待办事项。

todo.seletor.ts

import {createFeatureSelector, createSelector} from '@ngrx/store';
import {TodoState, selectAll, selectTotal} from '../Reducer/todo.reducers';
import {ITodo} from '../../../todo/todo';

export  interface AppState {
  todos: ITodo[];
}
export const selectorName = 'todos';
export const getTodoState = createFeatureSelector<TodoState>(selectorName);
// export const getTodoState = createSelector(todoFeatureSelector, state => state.entities);

export const todoCount = selectTotal;
// @ts-ignore
export const getTodos = createSelector(getTodoState, (state: AppState) => state.todos );
// export const getTodos = createSelector(getTodoState, selectAll );

// export const getTodoCount = createSelector(getTodoState, todoCount);

我在reducer状态下使用ngrx/entity。

todo.reducer.ts

import { ITodo, Todo } from '../../../todo/todo';
import { EntityAdapter, EntityState } from '@ngrx/entity/src/models';
import { createEntityAdapter } from '@ngrx/entity';
import {todoActions} from '../Actions/todo.action';
import {Action, createReducer, on, State} from '@ngrx/store';

export interface TodoState extends EntityState<ITodo> {
  error: string;
  message: string;
}

export const adapter: EntityAdapter<Todo> = createEntityAdapter<ITodo>();

export const initialTodoState: TodoState = adapter.getInitialState({
  error: null,
  message: null
});

export const todoReducer = createReducer(
  initialTodoState,
  on(todoActions.getTodoRequest, (state, action) => {
      return adapter.removeAll({...state, error: null});
    }
  ),
  on(todoActions.getTodoFailure, (state, action) => {
    return {...state, error: action.payload};
  }),
  on(todoActions.getTodoSuccess, (state, action) => {
    return adapter.setAll(action.todo, {...state});
  }),
  on(todoActions.addTodoSuccess, (state, action) => {
    return adapter.addOne(action.payload, {...state, error: null});
  }),
  on(todoActions.updateTodoRequest, (state, action) => {
    return adapter.updateOne(action.update, {...state, error: null});
  }),
  on(todoActions.updateTodoSuccess, (state, action) => {
    return adapter.addOne(action.payload, {...state, error: null});
  }),
  on(todoActions.updateTodoFailure, (state, action) => ({...state, error: action.payload})
  ),
  on(todoActions.deleteTodoRequest, (state, action) => {
      return adapter.removeOne(action.todoID, {...state, error: null, message: null});
    }
  ),
  on(todoActions.deleteTodoSuccess, (state, action) => {
    return {...state, error: null, message: action.message};
  }),
  on(todoActions.deleteTodoFailure, (state, action) => {
    return {...state, error: action.payload, message: null};
  })
);

export const {
  selectAll,
  selectIds,
  selectTotal,
  selectEntities
} = adapter.getSelectors();

我已经尝试过,但这些对我不起作用。我一直在为这个问题苦苦挣扎。

<div *ngIf="user$ | async; let user">
  <h3> {{user.name}}
</div>
<div *ngIf="(primitive$ | async) || ' '; let primitive">
  <h3> {{primitive}}
</div>
<div *ngIf="(user$ | async) || {}; let user">
  <h3> {{user?.name}}
</div>

TodoListComponent/index.ts

import {ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, Output} from '@angular/core';
import {ITodo, Todo} from '../../../todo/todo';
import {select, Store} from '@ngrx/store';
import {TodoState} from '../../store/Reducer/todo.reducers';

@Component({
  selector: 'app-todo-list',
  templateUrl: './index.html',
  styleUrls: ['./todoList.component.css'],
})
export class TodoListComponent {
  @Input()
  todos: ITodo[];

  @Output()
  remove: EventEmitter<Todo> = new EventEmitter();

  @Output()
  toggleComplete: EventEmitter<Todo> = new EventEmitter();

  constructor(
    private store: Store<TodoState>
  ) {}
// todoCount = this.store.pipe(select(getTodoCount));
  onToggleTodoComplete(todo: Todo) {
    this.toggleComplete.emit(todo);

  }
  onRemoveTodo(todo: Todo) {
    this.remove.emit(todo);

  }
}

TodoListComponent/index.html

  <div *ngIf="!(todoCount | async)" class="view" style=";">
    No Todo at the moment
  </div>

<section class="main" *ngIf="(todoCount | async) > 0">
  <ul class="todo-list">
    <li *ngFor="let todo of todos" [class.completed]="todo.complete">
      <app-todo-list-item
        [todo]="todo"
        (toggleComplete)="onToggleTodoComplete($event)"
        (remove)="onRemoveTodo($event)"
      ></app-todo-list-item>
    </li>
  </ul>
</section>

TodoListItemComponents/index.html

<div class="view">
  <div fxLayout="row" fxLayoutAlign="center center">
    <div fxFlex="50%">
      <mat-checkbox
        (click)="onToggleTodoComplete(todo)"
        [checked]="todo.complete"
        [style]="todo.complete?'text-decoration: line-through':''"
        color="primary"
        >{{todo?.title}}</mat-checkbox
      >
    </div>
    <div fxFlex="20%" style="padding: 5px;">
      <button
        mat-flat-button
        style="
          background-color: #dc3545;
          border-color: #dc3545;
          width: 20px;
          min-width: 36px;
        "
        class="destroy"
        (click)="onRemoveTodo(todo)"
      >
        <span style="color: white;">
          X
        </span>
      </button>
    </div>
    <div fxFlex="20%" style="padding: 5px;">
      <button
        mat-flat-button
        style="
          background-color: #dc3545;
          border-color: #dc3545;
          width: 20px;
          min-width: 36px;
        "
        class="destroy"
        (click)="editTodo(todo.id)"
      >
        <app-edit-icon style="position:relative;right:10px;top:4px" ></app-edit-icon>
      </button>
    </div>
  </div>
</div>

TodoListItemComponents/index.ts


import {
  ChangeDetectionStrategy, ChangeDetectorRef,
  Component,
  EventEmitter,
  Input,
  OnChanges,
  OnInit,
  Output
} from '@angular/core';
import {ITodo, Todo} from '../../../../../todo/todo';
import { TodoDataService } from '../../../../Services/API/todo-data.service';
import { UpdateTodoModalComponent } from '../update-todo-modal/update-todo-modal.component';
import { BsModalService, BsModalRef } from 'ngx-bootstrap/modal';

@Component({
  selector: 'app-todo-list-item',
  templateUrl: './index.html',
  styleUrls: ['./index.css'],
  changeDetection: ChangeDetectionStrategy.Default

})
export class TodoListItemComponent implements OnInit {
  bsModalRef: BsModalRef;
  @Input()
  todo: ITodo;
  todos: ITodo[];

  @Output()
  remove: EventEmitter<Todo> = new EventEmitter();

  @Output()
  toggleComplete: EventEmitter<Todo> = new EventEmitter();

  constructor(
    private todoDataService: TodoDataService,
    private bsModalService: BsModalService,
    private ref: ChangeDetectorRef
  ) {
  }

  ngOnInit() {
    this.getTodoList();
  }

  editTodo(todoId: number) {
    const initialState = {
      data: this.todos,
      id: todoId,
      ignoreBackdropClick: true,
      animated: true,
      keyboard: true,
    };
    this.bsModalRef = this.bsModalService.show(UpdateTodoModalComponent, {
      initialState,
    });
    this.bsModalRef.content.event.subscribe((result) => {
      if (result === 'Ok') {
        // this.getTodoList();
      }
    });
  }
  getTodoList() {
      this.todoDataService.getTodos().subscribe((todos) => {
        this.todos = todos;
        this.ref.detectChanges();
      });
  }
  onToggleTodoComplete(todo: Todo) {
    this.toggleComplete.emit(todo);
  }
  onRemoveTodo(todo: Todo) {
    this.remove.emit(todo);
  }
}

我希望列表应该将数据显示为 页面不显示数据

【问题讨论】:

  • 抱歉,对这种语法不是很熟悉。你没有使用 *ngFor 有什么原因吗?
  • 哪个部分给出了输出?那是TodosCompenent/index.html 吗?具体是哪一部分?你那里也有两个子组件。请指定究竟是哪个部分导致了该输出。
  • @Rick 我在 app-todo-list 中使用 *ngfor
  • @ulmas
  • 您希望在模板中看到什么?您确实将一个对象传递给 Todo List 组件,以便它向您显示正确的值。

标签: angular typescript ngrx ngrx-store


【解决方案1】:

您不应该检查生成的 html,它不会解决问题。

*ngIf="todo$ | async as todos" 是在模板中获取数据的正确方法。

如果您没有看到待办事项,您需要调试您的商店以确保它具有预期状态并正确减少操作。

最好的方法是使用store-devtools

在它的帮助下,您可以浏览商店并找到答案。

首先检查一个操作是否真的将待办事项添加到存储中。当它工作并且您看到所需的状态时,检查选择器的工作方式。您已经评论了 getTodos = createSelector(getTodoState, selectAll ) 之类的代码 - 这是使用 ngrx/entity 的正确方法。

如果商店有数据但选择器没有获取数据,你可以在不同的地方使用tap(console.log) 来检查选择器有什么,例如:

todo$ = this.store.pipe(select(getTodos), tap(console.log));

现在我们可以在控制台看到返回的数据了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-28
    • 1970-01-01
    • 2019-09-22
    • 1970-01-01
    • 2019-06-05
    • 2018-11-19
    • 2019-06-27
    • 2018-05-23
    相关资源
    最近更新 更多