首页 > 解决方案 > Ionic 3 - 存储只保留一次

问题描述

好的,所以这是一个奇怪的问题,我确信对此有一个很好的解释,但它让我无法理解。基础知识:


这是有问题的提供商:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Storage } from '@ionic/storage';


@Injectable()
export class GoalproviderProvider {

  public all_goals:any = [];
  public viewed_tutorial = false;

  public style_options = [
    {
      style_name: "girl-and-dog",
      style_color: "#5bc3cc",
      style_icon: "md-paw",
      style_icon_color: "#FFFFFF",
      mood: "Joyous"
    },
    {
      style_name: "pink-city",
      style_color: "#f7ced9",
      style_icon: "md-radio",
      style_icon_color: "#FFFFFF",
      mood: "Serene"
    },
    {
      style_name: "snow-guy",
      style_color: "#b4cbb9",
      style_icon: "md-snow",
      style_icon_color: "#FFFFFF",
      mood: "Confident"
    },
    {
      style_name: "fish-shop",
      style_color: "#31c1e9",
      style_icon: "md-rainy",
      style_icon_color: "#FFFFFF",
      mood: "Relaxed"
    }
  ];

  constructor(public http: HttpClient,
              private storage: Storage) {
    console.log('Loading Goals');
    this.LoadGoals();
  }

  public ClearAllData() {
    this.storage.clear();
  }

  public GetWatchedGoals() {
    var watched_goals = [];
    var i = 0;
    while(i < this.all_goals.length) {
      var k = 0;
      while(k < this.all_goals[i].goal_list.length) {
        var child_watched_goals = this.GetWatchedGoalsRecursively(this.all_goals[i].goal_list[k]);
        watched_goals = watched_goals.concat(child_watched_goals);
        k++;
      }
      i++;
    }
    return watched_goals;
  }

  public GetWatchedGoalsRecursively(goal) {
    var watched_goals = [];
    if(goal.goal_watch && !goal.goal_complete && !goal.goal_deleted)
      watched_goals.push(goal);
    var i = 0;
    while(i < goal.goal_list.length) {
      var child_watched_goals = this.GetWatchedGoalsRecursively(goal.goal_list[i]);
      watched_goals = watched_goals.concat(child_watched_goals);
      i++;
    }
    return watched_goals;
  }

  public AppendAndReturnNewGoal(goal_style, goal_title) {
    var new_goal = {
      goal_style: goal_style,
      goal_title: goal_title,
      goal_list: [],
      goal_id: new Date().getUTCMilliseconds()
    };
    this.all_goals.push(new_goal);
    this.LogGoals();
    return new_goal;
  }

  public EditGoalTitle(goal, new_title) {
    goal.goal_title = new_title;
    this.LogGoals();
  }

  public AddGoalChild(goal, new_title) {
    var new_goal = {
      goal_title: new_title,
      goal_watch: false,
      goal_complete: false,
      goal_deleted: false,
      goal_list: [],
      goal_id: new Date().getUTCMilliseconds()
    }
    goal.goal_list.push(new_goal);
    this.LogGoals();
  }

  public AddGoalParent(goal, new_title) {
    var new_goal = {
      goal_title: goal.goal_title,
      goal_watch: goal.goal_watch,
      goal_complete: goal.goal_complete,
      goal_deleted: goal.goal_deleted,
      goal_list: goal.goal_list,
      goal_id: goal.goal_id
    }
    goal.goal_title = new_title;
    goal.goal_watch = false;
    goal.goal_complete = false;
    goal.goal_deleted = false;
    goal.goal_list = [ new_goal ];
    goal.goal_id = new Date().getUTCMilliseconds();
    this.LogGoals();
  }

  public DeleteGoal(goal) {
    goal.goal_deleted = true;
    this.LogGoals();
  }

  public ToggleGoalComplete(goal) {
    goal.goal_complete = !goal.goal_complete;
    this.LogGoals();
  }

  public ToggleGoalWatch(goal) {
    goal.goal_watch = !goal.goal_watch;
    this.LogGoals();
  }

  public UpdateMasterGoal(goal_id, new_goal) {

  }

  LogGoals() {
    // TODO : I THINK WE HAVE TO TIMEOUT THIS FUNCTION TO ALLOW "ALL_GOALS" TO CATCH UP.
    console.log('GOAL LOG:', this.all_goals);
    this.storage.set('all_goals', this.all_goals);
  }

  LoadGoals() {
    this.all_goals = [];
    this.storage.get('all_goals').then((val) => {
      if(!val) {
        val = [];
        this.storage.set('all_goals', val);
      }
      console.log('GOALS LOADED FROM STORAGE:', val);
      this.all_goals = val;
    });
  }
}


在这个片段中,我有一个变量all_goals. 该变量连接到一系列递归组件,这些组件能够更新/操作各自的目标。

组件:

import { Component } from '@angular/core';
import { Input } from '@angular/core';
import { ActionSheetController, AlertController } from 'ionic-angular';

import { GoalproviderProvider } from '../../providers/goalprovider/goalprovider';
import { MonetizationProvider } from '../../providers/monetization/monetization';


@Component({
  selector: 'goalem-list',
  templateUrl: 'goalem.html'
})
export class GoalemComponent {

	@Input() goal_list;
	@Input() search_term;
	@Input() nested_level;

	constructor(public actionSheetCtrl: ActionSheetController,
				public alertCtrl: AlertController,
				public goal_provider: GoalproviderProvider,
				public monetization_provider: MonetizationProvider) {
		
	}

  	PresentActionSheet(goal) {
	  const actionSheet = this.actionSheetCtrl.create({
	    title: goal.goal_title,
	    buttons: [
	      {
	        text: 'Add Step',
	        icon: 'add-circle',
	        handler: () => {
	          console.log('Add Child Step');
	          this.PresentAddChildPopup(goal);
	        }
	      },
	      {
	        text: 'Add Parent Step',
	        icon: 'add-circle',
	        handler: () => {
	          console.log('Add Parent Step');
	          this.PresentAddParentPopup(goal);
	        }
	      },
	      {
	        text: goal.goal_complete ? 'Mark Incomplete' : 'Mark Complete',
	        icon: goal.goal_complete ? 'close-circle' : 'checkmark-circle',
	        handler: () => {
	          console.log('Check Off');
	          this.goal_provider.ToggleGoalComplete(goal);
	        }
	      },
	      {
	        text: 'Edit',
	        icon: 'build',
	        handler: () => {
	          console.log('Edit Goal');
	          this.PresentEditPopup(goal);
	        }
	      },
	      {
	        text: goal.goal_watch ? 'Stop Watching' : 'Watch',
	        icon: goal.goal_watch ? 'eye-off' : 'eye',
	        handler: () => {
	          console.log('Watch Goal');
	          this.goal_provider.ToggleGoalWatch(goal);
	        }
	      },
	      {
	        text: 'Delete',
	        icon: 'trash',
	        role: 'destructive',
	        handler: () => {
	          console.log('Delete Goal');
	          this.PromptConfirmDelete(goal);
	        }
	      },
	      {
	        text: 'Cancel',
	        icon: 'close',
	        role: 'cancel',
	        handler: () => {
	          console.log('Cancel clicked');
	        }
	      }
	    ]
	  });
	  actionSheet.present();
	}

	PresentEditPopup(goal) {
	    const prompt = this.alertCtrl.create({
	      title: 'Edit Step',
	      message: "Enter a description for this step.",
	      inputs: [
	        {
	          name: 'title',
	          placeholder: 'Description...',
	          value: goal.goal_title
	        },
	      ],
	      buttons: [
	        {
	          text: 'Cancel',
	          handler: data => {
	            console.log('Cancel clicked');
	          }
	        },
	        {
	          text: 'Submit',
	          handler: data => {
	            this.goal_provider.EditGoalTitle(goal, data.title);
	          }
	        }
	      ]
	    });
	    prompt.present();
  	}

  	PresentAddChildPopup(goal) {
  		if(this.nested_level > 3) {
  			var limit_title = "It's goals all the way down, mate.";
      		var limit_description = "You've discovered a premium feature! To unlock your app's true potential, click the button below. Your donation helps cover our operating costs, allowing us to continue providing the fantastic service you deserve!";
      		if(this.monetization_provider.PromptUpgradeIfNotPremium(limit_title, limit_description))
        		return;
  		}
	    const prompt = this.alertCtrl.create({
	      title: 'Create Step',
	      message: "Enter a description for this step.",
	      inputs: [
	        {
	          name: 'title',
	          placeholder: 'Description...'
	        },
	      ],
	      buttons: [
	        {
	          text: 'Cancel',
	          handler: data => {
	            console.log('Cancel clicked');
	          }
	        },
	        {
	          text: 'Submit',
	          handler: data => {
	            this.goal_provider.AddGoalChild(goal, data.title);
	          }
	        }
	      ]
	    });
	    prompt.present();
  	}

  	PresentAddParentPopup(goal) {
	    const prompt = this.alertCtrl.create({
	      title: 'Create Step',
	      message: "Enter a description for this step.",
	      inputs: [
	        {
	          name: 'title',
	          placeholder: 'Description...'
	        },
	      ],
	      buttons: [
	        {
	          text: 'Cancel',
	          handler: data => {
	            console.log('Cancel clicked');
	          }
	        },
	        {
	          text: 'Submit',
	          handler: data => {
	            this.goal_provider.AddGoalParent(goal, data.title);
	          }
	        }
	      ]
	    });
	    prompt.present();
  	}

  	PromptConfirmDelete(goal) {
	    const confirm = this.alertCtrl.create({
	      title: 'Are You Sure?',
	      message: 'By deleting this step, you will also delete any children steps. This can not be undone. Continue?',
	      buttons: [
	        {
	          text: 'Cancel',
	          handler: () => {
	            console.log('Disagree clicked');
	          }
	        },
	        {
	          text: 'Okay',
	          handler: () => {
	            this.goal_provider.DeleteGoal(goal);
	          }
	        }
	      ]
	    });
	    confirm.present();
	}

}

<ul *ngIf="goal_list.length">
	<li *ngFor="let goal of goal_list">
		<ion-item class="goal-item" *ngIf="!goal.goal_deleted && (!search_term || goal.goal_title.toLowerCase().includes(search_term.toLowerCase()))">
	    	<p [ngStyle]="{'text-decoration': goal.goal_complete ? 'line-through' : 'none'}">{{goal.goal_title}}</p>
	    	<button ion-button clear item-end (tap)="PresentActionSheet(goal);">
	    		<ion-icon name="md-menu"></ion-icon>
	    	</button>
	  	</ion-item>
		<goalem-list [goal_list]="goal.goal_list" [search_term]="search_term" [nested_level]="nested_level + 1" *ngIf="goal.goal_list.length && !goal.goal_deleted"></goalem-list>
	</li>
</ul>

可以看到组件调用了自己。这将创建一系列嵌套的组件,这些组件反映了来自提供者的嵌套目标列表。

从功能上讲,除了保存之外,一切正常。这是我到目前为止发现的:

我有点疲惫,这已经接近我的技能边缘,所以不确定如何进行调试。作为参考,这里是调用根goal-list组件的页面。

<ion-header>
  <ion-navbar class="overlapping-navbar">
    <button ion-button menuToggle icon-only>
      <ion-icon name='menu'></ion-icon>
    </button>
    <ion-input [(ngModel)]="search_term" placeholder="Search..."></ion-input>
  </ion-navbar>
</ion-header>
<ion-content scroll="false" [ngStyle]="{'background-color': goal_color}">
  <div class="splash-bg">
    <img [src]="goal_image" />
  </div>
  <div class="splash-info">
    <!-- <div class="splash-logo"></div> -->
    <div class="splash-goal">
      <div>
        {{goal_title}}
      </div>
    </div>
  </div>
  <div class="goal-list">
    <goalem-list [goal_list]="goal_list" [search_term]="search_term" [nested_level]="1" *ngIf="goal_list"></goalem-list>
    <button class="rpg-button" ion-button icon-end large (click)="PromptForNewGoal()"
            style="margin:auto; display:block; margin-top:35px;">
        Map It!
    </button>
  </div>
</ion-content>

如果我可以做些什么来提供更多信息,请告诉我:) 我认为问题源于嵌套,但让我感到困惑的是它第一次起作用。这么奇怪...

标签: angularionic-frameworkionic3ionic-native

解决方案


推荐阅读