Заполнение таблицы с вкладками - PullRequest
0 голосов
/ 21 января 2020

Хорошо, я новичок в Angular, чуть меньше недели или около того, и мне удалось собрать большую часть этого приложения благодаря документации разработчика.

Я пытаюсь заполнить таблицу вкладок для вакансий, где нажатие на заголовок соответственно изменяет описание (например, здесь https://www.w3schools.com/w3css/tryit.asp?filename=tryw3css_tabulators_animate). Я заставил вкладки нормально работать с кодом stati c, но теперь пытаюсь извлечь из mongodb, он показывает только одну из записей в коллекции "posts", хотя весь массив объектов появляется в консоли .

Я не могу понять, что я делаю неправильно.

мой home.component. html:

    <div class="content" *ngFor="let post of posts">
      <div class="row">
        <div class="container">
          <div class="col-md-12 open">
            <h3>Open Positions:</h3>
          </div>
        </div>
      </div>
      <div class="example-loading-shade" *ngIf="isLoadingResults">
        <mat-spinner *ngIf="isLoadingResults"></mat-spinner>
      </div>
      <div class="row" [routerLink]="['/post']" >
        <div class="col-md-3" id="jobNames" data="this.posts">
          <div class="w3-bar w3-black">
            <button class="w3-bar-item w3-button tablink" onclick='openLink(event, post._id)'>{{post.postTitle}}</button>
          </div>
        </div>
        <div class="col-md-9" id="jobContainer">
          <div class="job w3-container w3-animate-opacity" id="post._id">
            <h3 class="jobSections">Date Posted: {{post.updated | date: 'dd MMM yyyy'}}</h3>
            <p [innerHTML]="post.postContent"></p>
          </div>
        </div>
      </div>

Пост. js:

    var mongoose = require('mongoose'), Schema = mongoose.Schema;

var PostSchema = new mongoose.Schema({
  category : { type: Schema.Types.ObjectId, ref: 'Category' },
  id: String,
  postTitle: String,
  postAuthor: String,
  postContent: String,
  postReference: String,
  created: { type: Date },
  updated: { type: Date, default: Date.now },
});

module.exports = mongoose.model('Post', PostSchema);

home.component.ts

import { Component, OnInit } from '@angular/core';
import { Post } from '../post/post';
import { PostService } from '../post.service';
import { HomeService } from '../home.service';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
  post: Post = {
    category: '',
    id: '',
    postTitle: '',
    postAuthor: '',
    postContent: '',
    postReference: '',
    created: null,
    updated: null
  };
  posts: Post[] = [];
  isLoadingResults = true;

  constructor(private api: HomeService) { }

  ngOnInit() {
    this.api.getPosts()
      .subscribe((res: any) => {
        this.posts = res;
        console.log(this.posts);
        this.isLoadingResults = false;
      }, err => {
        console.log(err);
        this.isLoadingResults = false;
      });
  }

}

заданий. js

function openLink(evt, animName) {
  var i, x, tablinks;
  x = document.getElementsByClassName("job");
  for (i = 0; i < x.length; i++) {
    x[i].style.display = "none";
  }
  tablinks = document.getElementsByClassName("tablink");
  for (i = 0; i < x.length; i++) {
    tablinks[i].className = tablinks[i].className.replace(" w3-red", "");
  }
  document.getElementById(animName).style.display = "block";
  evt.currentTarget.className += " w3-red";
}

home.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';
import { Category } from './category/category';
import { Post } from './post/post';

const apiUrl = 'http://localhost:3000/api/public/';

@Injectable({
  providedIn: 'root'
})
export class HomeService {

  constructor(private http: HttpClient) { }

  getCategories(): Observable<Category[]> {
    return this.http.get<Category[]>(apiUrl + 'category')
      .pipe(
        tap(_ => this.log('fetched Categories')),
        catchError(this.handleError('getCategories', []))
      );
  }

  getPosts(): Observable<Post[]> {
    return this.http.get<Post[]>(apiUrl + 'post')
      .pipe(
        tap(_ => this.log('fetched Posts')),
        catchError(this.handleError('getPosts', []))
      );
  }

  getPostsByCategory(id: any): Observable<Post[]> {
    return this.http.get<Post[]>(apiUrl + 'bycategory/' + id)
      .pipe(
        tap(_ => this.log('fetched Posts')),
        catchError(this.handleError('getPosts', []))
      );
  }

  getPost(id: any): Observable<Post> {
    return this.http.get<Post>(apiUrl + 'post/' + id).pipe(
      tap(_ => console.log(`fetched post by id=${id}`)),
      catchError(this.handleError<Post>(`getPost id=${id}`))
    );
  }

  private handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {

      console.error(error); // log to console instead
      this.log(`${operation} failed: ${error.message}`);

      return of(result as T);
    };
  }

  private log(message: string) {
    console.log(message);
  }
}

Ответы [ 2 ]

0 голосов
/ 22 января 2020

Я получил это, и в случае, если кто-то еще ищет что-то подобное

home.component.ts:

import { Component, OnInit } from '@angular/core';
import { Post } from '../post/post';
import { PostService } from '../post.service';
import { HomeService } from '../home.service';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
  post: Post = {
    category: '',
    id: '',
    postTitle: '',
    postAuthor: '',
    postContent: '',
    postReference: '',
    created: null,
    updated: null
  };
  posts: Post[] = [];
  isLoadingResults = true;
  selectedPost: Post = null;

  constructor(private api: HomeService) { }

  openLink(evt, animName) {
    var i, x, tablinks;
    x = document.getElementsByClassName("job");
    for (i = 0; i < x.length; i++) {
      x[i].style.display = "none";
    }
    tablinks = document.getElementsByClassName("tablink");
    for (i = 0; i < x.length; i++) {
      tablinks[i].className = tablinks[i].className.replace(" w3-red", "");
    }
    document.getElementById(animName).style.display = "block";
    evt.currentTarget.className += " w3-red";
  }

  selectPost(post) {
    this.selectedPost = post;
    console.log(this.selectedPost);
  }

  ngOnInit() {
    this.api.getPosts()
      .subscribe((res: any) => {
        this.posts = res;
        console.log(this.posts);
        this.isLoadingResults = false;
      }, err => {
        console.log(err);
        this.isLoadingResults = false;
      }
    );
  }

}

home.component. html

<div class="col-md-12 open">
        <h3>Open Positions:</h3>
      </div>
      <div class="example-loading-shade" *ngIf="isLoadingResults">
        <mat-spinner *ngIf="isLoadingResults"></mat-spinner>
      </div>
      <div class="row">
        <div class="col-md-2" id="jobNames">
          <div class="w3-bar w3-black">
            <button class="w3-bar-item w3-button tablink" *ngFor="let post of posts"
              (click)="selectPost(post)">{{post.postTitle}}</button>
          </div>
        </div>
        <div class="col-md-10" id="jobContainer">
          <div class="job w3-container w3-animate-opacity" id="{{selectedPost.postTitle}}">
            <h3 class="jobSections">Date Posted: {{selectedPost.updated | date: 'dd MMM yyyy'}}</h3>
            <p innerHTML={{selectedPost.postContent}}></p>
          </div>
        </div>
      </div>
0 голосов
/ 21 января 2020

Я не знаю, как устроен ваш HomeService , но ...

Хорошее решение - сделать в вашей службе метод getPosts с параметром, подобным section o имя вкладки и вы можете фильтровать данные с ним

Затем вы можете легко использовать его на HomeComponent

ngOnInit() {
  this.loadPosts('jobs'); // use first tab for default on load component
}

loadPosts(tabName) {
   this.api.getPosts(tanName)
      .subscribe((res: any) => {
        this.posts = res;
        console.log(this.posts);
        this.isLoadingResults = false;
      }, err => {
        console.log(err);
        this.isLoadingResults = false;
      });
}

, затем вы можете использовать его при нажатии

openLink(evt, animName) {
  /* your code */
  evt.currentTarget.className += " w3-red";
  let tabName = evt,currentTarget.innerText.trim() // trim(), maybe forget spaces  
  this.loadPosts(tabName);
}

если вам нужно обойтись без параметра, можно использовать конвейерный фильтр или иметь переменную для всех данных и другую для отфильтрованных данных, то при нажатии вы меняете отфильтрованные данные

ngOnInit() {
    this.api.getPosts()
      .subscribe((res: any) => {
        this.allPosts = res;      // <----- all post in a variable
        console.log(this.posts);
        this.isLoadingResults = false;
      }, err => {
        console.log(err);
        this.isLoadingResults = false;
      });
}

openLink(evt, animName) {
  /* your code */
  evt.currentTarget.className += " w3-red";
  let tabName = evt,currentTarget.innerText.trim() // trim(), maybe forget spaces
  this.posts = this.allPosts.filter(post=> post.tabName == 'tabName');
}

Редактировать

если вы выберете первый вариант, лучшим способом будет фильтрация на сервере при получении параметра tabName по запросу API, тогда воли c создаются на стороне сервера

export class HomeService {

  constructor(private http: HttpClient) { } 

  getPosts(tabName: string): Observable<Post[]> {
    return this.http.get<Post[]>(apiUrl + 'post?tabName='+tabName)
      .pipe(
        tap(_ => this.log('fetched Posts')),
        catchError(this.handleError('getPosts', []))
      );
  } 
}
...