添加类别/子类别后角度更新视图

问题描述 投票:0回答:0

我已经实现了从类别或子类别添加子类别的功能。但是视图没有更新,它需要重新加载来更新视图。 在这里,我以嵌套方式显示我的类别数据,并通过递归组件完成。 我的类别组件:

  import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { CategoryService } from 'src/app/services/category.service';
import { concatMap } from 'rxjs/operators';

@Component({
  selector: 'app-categories',
  templateUrl: './categories.component.html',
  styleUrls: ['./categories.component.css'],
})
export class CategoriesComponent implements OnInit {
  categories: any = [];
  categoryTree: any = [];
  categoryMap: any = [];
  categoryIdToDelete: any;
  selectedParent: any = null;

  addCategoryForm!: FormGroup;
  saveButtonText: string = 'Save';

  // toggle title
  addingSubcategory: boolean = false;

  toggleAddingSubcategory(parentCategory: any) {
    console.log(parentCategory);
    this.addingSubcategory = true;
    this.selectedParent = parentCategory;
    this.addCategoryForm.controls['parent'].setValue(parentCategory);
    console.log(this.addCategoryForm.value);
  }

  toggleAddingCategory() {
    this.addingSubcategory = false;
  }

  // set active tab dynamically
  activeTabIndex: number = 0;

  setActiveTab(index: number) {
    this.activeTabIndex = index;
  }

  constructor(
    private categoryService: CategoryService,
    private cdr: ChangeDetectorRef
  ) {}

  ngOnInit(): void {
    // dummy object
    // {
    //   "name": "Keto Child 1.1.1",
    //   "shortText": "",
    //   "longText": "",
    //   "media": [],
    //   "parent": "6434fb5e0dccedc460b6575a",
    //   "subCategories": []
    // }

    this.addCategoryForm = new FormGroup({
      name: new FormControl(''),
      shortText: new FormControl(''),
      longText: new FormControl(''),
      media: new FormControl([]),
      parent: new FormControl(''),
      subCategories: new FormControl([]),
    });

    // to show categories
    this.categoryService.getCategories().subscribe((res: any) => {
      this.categories = res.result;
      console.log(this.categories);
      this.buildCategoryTree();
    });
  }

  // this function is used to make category tree in nested way
  private buildCategoryTree() {
    //to map the categories by id with updated categories
    const categoryMap = [];
    for (const category of this.categories) {
      categoryMap[category.id] = { ...category, subCategories: [] };
    }

    //to build the category tree with updated categories
    const categoryTree = [];
    for (const category of this.categories) {
      if (category.parent === null) {
        categoryTree.push(categoryMap[category.id]);
      } else {
        const parentCategory = categoryMap[category.parent];
        if (parentCategory) {
          parentCategory.subCategories.push(categoryMap[category.id]);
        }
      }
    }

    this.categoryTree = categoryTree;
    console.log(categoryTree);
  }

  addCategories() {
    this.saveButtonText = 'Saving';
    const formData = this.addCategoryForm.value;

    this.categoryService
      .addCategories(formData, formData.parent)
      .pipe(
        concatMap((response) => {
          return this.categoryService.getCategories();
        })
      )
      .subscribe((res: any) => {
        // find the parent category/subcategory by its id
        const parent = formData.parent
          ? this.findSubcategoryById(formData.parent, this.categories)
          : this.categories.find((c: any) => c.id === formData.parent);

        if (parent) {
          // push the new category/subcategory to the parent's subCategories array
          if (!parent.subCategories) {
            parent.subCategories = [];
          }
          parent.subCategories.push(res.newCategory);

          // re-build the category tree with the updated categories data
          this.buildCategoryTree();
          this.cdr.detectChanges();
        }

        this.saveButtonText = 'Saved';
        this.addCategoryForm.reset();
      });
  }

  addSubcategory(parentSubcategoryId: any) {
    this.addCategoryForm.controls['parent'].setValue(parentSubcategoryId);
    const formData = this.addCategoryForm.value;

    this.categoryService
      .addCategories(formData, formData.parent)
      .pipe(
        concatMap((response) => {
          return this.categoryService.getCategories();
        })
      ) // set the parent subcategory id
      .subscribe((res: any) => {
        // find the parent subcategory by its id
        const parentSubcategory = this.findSubcategoryById(
          parentSubcategoryId,
          this.categories
        );

        if (parentSubcategory) {
          // push the new subcategory to the parent subcategory's subCategories array
          if (!parentSubcategory.subCategories) {
            parentSubcategory.subCategories = [];
          }
          parentSubcategory.subCategories.push(res.newCategory);

          // re-build the category tree with the updated categories data
          this.buildCategoryTree();
          this.cdr.detectChanges();
        }

        this.saveButtonText = 'Saved';
        this.addCategoryForm.reset();
      });
  }

  // recursive function to find a subcategory by its id
  findSubcategoryById(id: string, categories: any[]): any {
    for (const category of categories) {
      if (category.id === id) {
        return category;
      } else if (category.subCategories) {
        const subcategory = this.findSubcategoryById(
          id,
          category.subCategories
        );
        if (subcategory) {
          return subcategory;
        }
      }
    }
    return null;
  }
}

你可以在这里看到,我已经尝试了两种方法来使用 ChangeDetectorRef 更新视图,并使用单独的函数使用更新的类别数据重建类别树。但它不起作用。谁能帮我克服这种情况?服务和递归组件已在下面给出以理解概念。

递归组件:

import { Component, Input, EventEmitter, Output, OnInit } from '@angular/core';

export class subCategories {
  id: string = '';
  name: string = '';
  shortText: string = '';
  longText: string = '';
  parent: string = '';
  media: Array<string>[] = [];
  subCategories: subCategories[] = [];
}

@Component({
  selector: 'app-recursive',
  templateUrl: './recursive.component.html',
  styleUrls: ['./recursive.component.css'],
})
export class RecursiveComponent implements OnInit {
  @Input() subCategories: subCategories[] | undefined;
  @Output() deleteSubCategoryEvent = new EventEmitter<any>();
  @Output() addSubCategoryEvent = new EventEmitter<any>();

  ngOnInit(): void {}

  deleteSubcategory(subcategoryId: any) {
    this.deleteSubCategoryEvent.emit(subcategoryId);
  }

  addSubcategory(parent: any) {
    this.addSubCategoryEvent.emit(parent);
  }
}

服务:

  addCategories(categoryInfo: any, parentId: string | null): Observable<any> {
    const newCategory = {
      name: categoryInfo.name,
      shortText: categoryInfo.shortText,
      longText: categoryInfo.longText,
      media: categoryInfo.media,
      // set the parent id here
      parent: parentId,
      subCategories: [],
    };
    return this.http.post(
      'https://pim-nest.vercel.app/api/v1/collections/category',
      newCategory
    );
  }

我的看法,categories.html:

<div class="cms-body-content col-12">
  <div class="cms-body-inner-content accordion expander">
    <div class="expander-inner category" *ngFor="let category of categoryTree">
      <div class="expander-header" [id]="'heading-' + category.id">
        <div class="item btn-item">
          <div class="inner-cont" *ngIf="category.subCategories.length > 0; else nosubCategories">
            <span class="btn arrow collapsed" [attr.data-target]="'#collapse-' + category.id" data-toggle="collapse"
              aria-expanded="false">{{ category.name }}</span>
          </div>
          <ng-template #nosubCategories>
            <div class="inner-cont my-1">
              {{ category.name }}
            </div>
          </ng-template>
          <div class="more d-flex">
            <div class="icon-hover" data-toggle="tooltip" data-placement="top">
              <a class="icon-plus-circle fs20" data-target="#addCategoryModal" data-toggle="modal"
                (click)="toggleAddingSubcategory(category.id)"></a>
            </div>
            <div class="dropdown">
              <span class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
                <i class="fal fa-ellipsis-v"></i>
              </span>
              <div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton">
                <a class="dropdown-item" href="#" data-target="#editCategoryModal" data-toggle="modal">Edit</a>
                <a class="dropdown-item" href="#" data-target="#deleteModal" data-toggle="modal"
                  (click)="categoryIdToDelete = category.id">Delete</a>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div [id]="'collapse-' + category.id" class="collapse" [attr.aria-labelledby]="'heading-' + category.id">
        <div class="expander-body">
          <app-recursive [subCategories]="category.subCategories" (deleteSubCategoryEvent)="deleteSubCategory($event)"
            (addSubCategoryEvent)="addSubcategory($event)"></app-recursive>
        </div>
      </div>
    </div>
  </div>
</div>

<!-- add category button(plus button) -->
<button data-target="#addCategoryModal" data-toggle="modal" type="button" class="btn btn-add cms-add-btn add-category"
  (click)="toggleAddingCategory()"></button>

<!-- Add category modal -->
<div id="addCategoryModal" class="modal fade right add-category-modal" tabindex="-1">
  <div class="modal-dialog">
    <form class="modal-content ng-untouched ng-pristine ng-invalid" [formGroup]="addCategoryForm">
      <div class="modal-header left-icon-tab">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <i class="icon-close"></i>
        </button>
        <ul class="modal-tab nav-tabs">
          <li class="tab-item" [ngClass]="{ 'active': activeTabIndex === 0 }">
            <a href="#newCategory" data-toggle="tab" (click)="setActiveTab(0)"> {{ addingSubcategory ? 'New subcategory'
              : 'New category' }} </a>
          </li>
          <li class="tab-item" [ngClass]="{ 'active': activeTabIndex === 1 }">
            <a href="#bulk" data-toggle="tab" (click)="setActiveTab(1)"> {{ addingSubcategory ? '' : 'Bulk Add' }} </a>
          </li>
        </ul>
      </div>

      <div class="modal-body tab-content">
        <div class="tab-pane active" id="newCategory">
          <div class="form-group">
            <input type="text" class="form-control" formControlName="name" placeholder="Category name" />
          </div>

          <h5 class="brand-secondary pt-3 mb-3">Descriptions</h5>
          <div class="form-group">
            <label class="brand-secondary mb-0">Short text</label>
            <p class="p-extra-small gray-darker mb-2">Short text is displayed under the category heading in a
              site catalog</p>
            <textarea class="form-control" formControlName="shortText" rows="3"></textarea>
          </div>

          <div class="form-group">
            <label class="brand-secondary mb-0">Long text</label>
            <p class="p-extra-small gray-darker mb-2">Long text is displayed in the product catalog as a
              separate section after the title and short text</p>
            <textarea class="form-control" formControlName="longText" rows="6"></textarea>
          </div>

          <div class="form-group">
            <label class="brand-secondary mb-0">Media</label>
            <div class="dragbox-outer">
              <div class="dragBox">
                <p class="drag-icon"></p>
                <p class="drag-text p-medium-bold gray-dark">Drop files or click to select</p>
                <input type="file" onchange="dragNdrop(event)" ondragover="drag()" ondrop="drop()" id="uploadFile"
                  class="uploadFile">
              </div>
            </div>
          </div>

          <div class="form-group" *ngIf="!addingSubcategory">
            <h5 class="brand-secondary pt-3 mb-3">Subcategories</h5>
            <p class="p-extra-small gray-darker mb-2">Enter subcategories separated by a line break. Use TAB button on
              your keyboard to add another nesting level.</p>
            <textarea class="form-control p-small ng-untouched ng-pristine ng-valid" rows="6">
            </textarea>
          </div>
        </div>

        <div class="tab-pane bulk" id="bulk">
          <div class="form-group">
            <p class="p-extra-small gray-darker mb-2">Enter categories separated by a line break. Use TAB button on
              your keyboard to add another nesting level.</p>
            <textarea class="form-control p-small" rows="25">
              </textarea>
          </div>
        </div>
      </div>

      <div class="modal-footer">
        <div class="bottom-bar">
          <div class="bottom-bar-left">
            <a type="button" (click)="addCategories()" class="btn btn-brand">{{saveButtonText}}</a>
            <a data-dismiss="modal" class="btn btn-gray">Cancel</a>
          </div>
        </div>
      </div>
    </form>
  </div>
</div>

和recursive.html:

<ul class="list">
  <li class="item-border" *ngFor="let subCategory of subCategories">
    <div class="expander-inner category" *ngIf="subCategory.subCategories.length > 0; else nosubCategories">
      <div class="expander-header" [id]="'heading-' + subCategory.id">
        <div class="item btn-item">
          <div class="inner-cont">
            <span class="btn arrow collapsed" [attr.data-target]="'#collapse-' + subCategory.id" data-toggle="collapse"
              aria-expanded="false">{{ subCategory.name }}</span>
          </div>
          <div class="more d-flex">
            <span class="icon-hover" data-toggle="tooltip" data-placement="top" title="New subcategory">
              <i class="icon-plus-circle" data-target="#addCategoryModal" data-toggle="modal"
                (click)="addSubcategory(subCategory.id)"></i>
            </span>
            <div class="dropdown">
              <span class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
                <i class="fal fa-ellipsis-v"></i>
              </span>
              <div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton">
                <a class="dropdown-item" href="#" data-target="#editCategoryModal" data-toggle="modal">Edit</a>
                <a class="dropdown-item" href="#" data-target="#deleteModal" data-toggle="modal"
                  (click)="deleteSubcategory(subCategory)">Delete</a>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div [id]="'collapse-' + subCategory.id" class="collapse" [attr.aria-labelledby]="'heading-' + subCategory.id">
        <app-recursive [subCategories]="subCategory.subCategories" (deleteSubCategoryEvent)="deleteSubcategory($event)"
          (addSubCategoryEvent)="addSubcategory($event)"></app-recursive>
      </div>
    </div>

    <ng-template #nosubCategories>
  <li class="item">
    <div class="inner-cont">
      <a class="dropdown-item" href="#" data-target="#editCategoryModal" data-toggle="modal">{{subCategory.name}}</a>
    </div>
    <div class="more d-flex">
      <span class="icon-hover" data-toggle="tooltip" data-placement="top" title="New subcategory">
        <i class="icon-plus-circle" data-target="#addCategoryModal" data-toggle="modal"
          (click)="addSubcategory(subCategory.id)"></i>
      </span>
      <div class="dropdown">
        <span class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
          <i class="fal fa-ellipsis-v"></i>
        </span>
        <div class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownMenuButton">
          <a class="dropdown-item" href="#" data-target="#editCategoryModal" data-toggle="modal">Edit</a>
          <a class="dropdown-item" href="#" data-target="#deleteModal" data-toggle="modal"
            (click)="deleteSubcategory(subCategory)">Delete</a>
        </div>
      </div>
    </div>
  </li>
  </ng-template>
  </li>
</ul>
angular typescript angular-services angular-httpclient
© www.soinside.com 2019 - 2024. All rights reserved.