删除对象项并将其添加到数组中,如果数组中已存在特定项,则更改对象键

我有这个食谱数组,其中每个对象都是一个特定的食谱,每个食谱都有一个成分数组,每个成分都是由_id name quantity. 如果你们知道为什么会这样,请在下面添加我的问题,请告诉我。我挣扎了 3 天......任何建议将不胜感激。多谢!


(3) [{…}, {…}, {…}]

0:

ingredients: Array(4)

0: {_id: "5f6628d0029e87e02c79ce0a", name: "chia", quantity: 10}

1: {_id: "5f6628d0029e87e02c79ce0b", name: "apple", quantity: 15}

2: {_id: "5f6628d0029e87e02c79ce0c", name: "honey", quantity: 30}

3: {_id: "5f6628d0029e87e02c79ce0d", name: "almond flour", quantity: 35}

length: 4

__proto__: Array(0)

name: "Coconut Chia Pudding"

__v: 0

_id: "5f6628d0029e87e02c79ce09"

__proto__: Object

1: {_id: "5f6628d0029e87e02c79ce0e", name: "Peanut Butter Cookies", ingredients: Array(4), __v: 0}

2: {_id: "5f6628d0029e87e02c79ce13", name: "Caprese Avocado Bowls", ingredients: Array(3), __v: 0}

length: 3

__proto__: Array(0)

我在 UI 中拥有的是一个包含上述食谱的列表,用户可以勾选和取消勾选,在勾选食谱后,其成分显示在列表中。


HTML


<ion-content>

  <ion-grid>

    <ion-row>

      <ion-col>

        <ion-list>

          <ion-item

            *ngFor="let recipe of loadedRecipes; let lastRecipe = last"

            [ngClass]="{ 'last-recipe': lastRecipe }"

          >

            <ion-checkbox

              (ionChange)="onCheckRecipe($event)"

              value="{{recipe.name}}"

            ></ion-checkbox>

            <ion-label>{{recipe.name}}</ion-label>

            <ion-button

              [routerLink]="['/','recipes','recipe-details', recipe._id]"

              >></ion-button

            >

          </ion-item>

        </ion-list>

      </ion-col>

    </ion-row>


    <ion-row>

      <ion-col>

        <h6 class="ion-padding-start" *ngIf="groceryList.length > 0">

          Grocery List

        </h6>

        <ion-list *ngIf="groceryList.length > 0">

          <ion-item *ngFor="let ingredient of groceryList">

            <ion-label>{{ingredient.name}}</ion-label>

            <ion-note slot="end">{{ingredient.quantity}} g</ion-note>

          </ion-item>

        </ion-list>

      </ion-col>

    </ion-row>

  </ion-grid>

</ion-content>


炎炎设计
浏览 107回答 2
2回答

慕村9548890

问题在于您的 if 语句的流程。在代码的“onRemove”部分,您说的是“如果成分在列表中,则将其从列表中删除。如果不在,则减少其数量。” 第二部分没有任何意义,更重要的是,你永远也做不到,因为成分应该总是在列表中。for (let eachIngredient of recipe.ingredients) {&nbsp; let matched = this.groceryList.find(function(foundIngre) {&nbsp; &nbsp; return foundIngre.name === eachIngredient.name;&nbsp; });&nbsp; if (&nbsp; &nbsp; matched.name === eachIngredient.name &&&nbsp; &nbsp; matched._id === eachIngredient._id&nbsp; ) {&nbsp; &nbsp; let index = this.groceryList.findIndex(&nbsp; &nbsp; &nbsp; (x) => x._id === matched._id&nbsp; &nbsp; );&nbsp; &nbsp; // Problem e ca eachIngredient.quantity se schimba&nbsp; &nbsp; this.groceryList.splice(index, 1);&nbsp; } else {&nbsp; &nbsp; matched.quantity = matched.quantity - eachIngredient.quantity;&nbsp; }}根据你所说的,你想要做的是:减去归因于已删除配方的数量如果新数量为零,则从列表中删除该成分(尽管您也可以保留它并忽略数量为零的成分)试试这个:for (let eachIngredient of recipe.ingredients) {&nbsp; // I am assuming that ids are unique so I am not checking foundIngre.name at all,&nbsp;&nbsp; // since I assume that ingredients with the same name must also have the same name&nbsp; // I am also using findIndex first so that you don't need a second find when removing&nbsp; const matchIndex = this.groceryList.findIndex(&nbsp;&nbsp; &nbsp; &nbsp;(foundIngre) => foundIngre._id === eachIngredient._id&nbsp; );&nbsp; if ( matchIndex ) { // this should always be true&nbsp; &nbsp; const matched = this.groceryList[matchIndex];&nbsp; &nbsp; // preserve the entry if there is still some quantity&nbsp; &nbsp; if ( matched.quantity > eachIngredient.quantity ) {&nbsp; &nbsp; &nbsp; matched.quantity = matched.quantity - eachIngredient.quantity; // can use -= to shorten&nbsp; &nbsp; }&nbsp; &nbsp; // remove from the list only if there is no quantity remaining&nbsp; &nbsp; else {&nbsp; &nbsp; &nbsp; &nbsp; this.groceryList.splice(matchIndex, 1);&nbsp; &nbsp; }&nbsp; }}编辑: 尝试更新和删除数组中的项目是一种不必要的痛苦。修改后的代码版本将 _groceryList 存储在键控字典中。我最初打算按成分 ID 键,但在查看您的演示后,我发现我的假设是错误的,即多个食谱中的相同成分将共享相同的 ID。所以我改为按成分名称键入。这样你就可以写入 _groceryList[name] 并且它以前是否存在并不重要。该类有一个公共的 getter groceryList,它将私有的 _groceryList 字典转换为一个数组。我还尝试通过使用一个通用toggleIngredient函数来消除场景分支中不必要的代码重复,该函数使用布尔值checked来控制它是通过乘以加号还是减号来控制加法或减法。import { Component } from "@angular/core";import { Platform } from "@ionic/angular";import { SplashScreen } from "@ionic-native/splash-screen/ngx";import { StatusBar } from "@ionic-native/status-bar/ngx";import { Subscription } from "rxjs";export interface Ingredient {&nbsp; _id: string;&nbsp; name: string;&nbsp; quantity: number;}export interface Recipe {&nbsp; _id: string;&nbsp; name: string;&nbsp; ingredients: Ingredient[];}@Component({&nbsp; selector: "app-root",&nbsp; templateUrl: "app.component.html"})export class AppComponent {&nbsp; private _recipesSub: Subscription;&nbsp; constructor(&nbsp; &nbsp; private platform: Platform,&nbsp; &nbsp; private splashScreen: SplashScreen,&nbsp; &nbsp; private statusBar: StatusBar,&nbsp; ) {&nbsp; &nbsp; this.initializeApp();&nbsp; }&nbsp; initializeApp() {&nbsp; &nbsp; this.platform.ready().then(() => {&nbsp; &nbsp; &nbsp; this.statusBar.styleDefault();&nbsp; &nbsp; &nbsp; this.splashScreen.hide();&nbsp; &nbsp; });&nbsp; }&nbsp; private loadedRecipes: Recipe[] = [/*...*/]&nbsp; // store the groceryList in a dictionary keyed by name&nbsp; private _groceryList: Record<string, Ingredient> = {};&nbsp; // getter returns the groceryList in array format, ignoring 0 quantities&nbsp; get groceryList(): Ingredient[] {&nbsp; &nbsp; return Object.values(this._groceryList).filter( ing => ing.quantity > 0 );&nbsp; }&nbsp; // get the current quantity for an ingredient by name, or 0 if not listed&nbsp; currentQuantity( name: string ): number {&nbsp; &nbsp; const ingredient = this._groceryList[name];&nbsp; &nbsp; return ingredient ? ingredient.quantity : 0;&nbsp; }&nbsp; // update the quantity for an ingredient when checked or unchecked&nbsp; // will add new ingredients, but never removes old ones&nbsp; toggleIngredient( ingredient: Ingredient, checked: boolean ): void {&nbsp; &nbsp; // add to or remove from quantity depending on the value of checked&nbsp; &nbsp; const quantity = this.currentQuantity(ingredient.name) + (checked ? 1 : -1 ) * ingredient.quantity;&nbsp; &nbsp; // replace the object in the grocery list dictionary&nbsp; &nbsp; this._groceryList[ingredient.name] = {&nbsp; &nbsp; &nbsp; ...ingredient,&nbsp; &nbsp; &nbsp; quantity&nbsp; &nbsp; }&nbsp; }&nbsp; onCheckRecipe(e) { // you'll want to add a type for e here&nbsp; &nbsp; for (let recipe of this.loadedRecipes) {&nbsp; &nbsp; &nbsp; // find the matching recipe&nbsp; &nbsp; &nbsp; &nbsp; if (recipe.name === e.detail.value) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // loop through the recipe ingredients&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (let eachIngredient of recipe.ingredients) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; this.toggleIngredient(eachIngredient, e.detail.checked)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; }&nbsp; }}

汪汪一只猫

我认为问题似乎出在代码的这一部分if (&nbsp; matched.name === eachIngredient.name &&&nbsp; matched._id === eachIngredient._id) {&nbsp; let index = this.groceryList.findIndex(&nbsp; &nbsp; (x) => x._id === matched._id&nbsp; );&nbsp; // Problem e ca eachIngredient.quantity se schimba&nbsp; this.groceryList.splice(index, 1);} else {&nbsp; matched.quantity = matched.quantity - eachIngredient.quantity;}if 语句应该检查数量而不是再次验证名称和 id ,比如if(matched.quantity <= eachIngredient.quantity){ // 拼接项目并删除它。} else { // 减少数量 }找到匹配成分的小建议。先用findIndex()检索matchedIndex,再用grocerylist[matchedIndex]检索item,避免再次遍历grocerylist寻找索引进行拼接。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript