Range and Label items not keeping value when other items change


#1

I’m dynamically rendering components in a page because depending on a user selection from a previous page these values will change in how they are displayed. I can’t make static pages because there are too many selection and thus too many pages to generate. Also if the data changes then these pages need to be updated dynamically. Here is the code.

Here is the html page

<!--
  Generated template for the FactorsPage page.

  See http://ionicframework.com/docs/components/#navigation for more info on
  Ionic pages and navigation.
-->
<ion-header>

  <ion-navbar>
    <ion-title>Make it Epic</ion-title>
  </ion-navbar>

</ion-header>


<ion-content no-bounce class="bg-image">

  <!-- This is the title for the month selection -->
  <div class="title-text top-title">
    Preferences
  </div>

  <!-- This will setup the segmant group top buttons -->
  <ion-segment *ngIf='renderContent' [(ngModel)]="preferences" padding>
    <ion-segment-button *ngFor="let activity of envFactors" value="{{activity.name}}" (click)="toggleGroup()">
      {{ activity.name }}
    </ion-segment-button>
  </ion-segment>

  <!-- This is looping through each of the groups and creating their sections for the buttons above -->
  <div [ngSwitch]="preferences">

    <!-- looping through all of the environment factor groups -->
    <div *ngFor="let factor of envFactors; let i = index">
      <!-- setup the switch case for each group -->
      <ion-list *ngSwitchCase="factor.name" class="accordion-list">
        <!-- looping through each of the factors and making list items for them -->
        <div *ngFor="let item of factor.factors; let ii = index" no-lines>

          <!-- Header section for each of the factors -->
          <button ion-item (click)="toggleSection(i, ii)" detail-none [ngClass]="{'section-active': item.open, 'section': !item.open}">
            <!-- Arrow that changes when clicked -->
            <ion-icon item-right name="arrow-forward" *ngIf="!item.open"></ion-icon>
            <ion-icon item-right name="arrow-down" *ngIf="item.open"></ion-icon>
            <!-- Content of header -->
            <h3>{{ item.name }}</h3>
            <p id="description">
              {{ item.description }}
            </p>
          </button>

          <!-- Content shows when header above is clicked -->
          <ion-list radio-group [(ngModel)]="userInput" *ngIf="item.open" no-lines no-padding>

            <!-- Slider dynamically displaying information if values are numbers-->
            <ion-item *ngIf="item.steps != 0">
              <ion-range (ionChange)="setFactors(item.name)" min="{{ getVal('min-max', 'start', item.threshold) }}" max="{{ getVal('min-max', 'end', item.threshold) }}" step="{{item.steps}}" snaps="true" pin="true" [(ngModel)]="userInput">
                <!-- Labels for the ends of the slider being displayed -->
                <ion-label range-left>
                  {{ getVal('label', 'start', item.threshold) }}
                </ion-label>
                <ion-label range-right>
                  {{ getVal('label', 'end', item.threshold) }}
                </ion-label>
              </ion-range>
            </ion-item>

            <!-- Radio dynamically displaying information if values are not numbers -->
            <div *ngIf="item.steps == 0">
              <ion-item *ngFor="let value of item.threshold; let v = index">
                <ion-label>{{ value }}</ion-label>
                <ion-radio (ionSelect)="setFactors(item.name)" value="{{ value }}"></ion-radio>
              </ion-item>
            </div>

          </ion-list>

        </div>
      </ion-list>
    </div>
  </div>

  <!-- Dynamically updated results after a change is made -->
  <div class="title-text bottom-title">
    {{ results.remaining }} / {{ results.total }} Destinations
  </div>

  <!-- A button to go to the next page -->
  <div>
    <button ion-button round class="next-button" (click)="goToNextPage()">
      LET'S RIP!
    </button>
  </div>

</ion-content>

Here is the typescript page

import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';

import { LocalStorageProvider } from './../../providers/local-storage/local-storage';
import { EnvCalculatorProvider } from '../../providers/env-calculator/env-calculator';

/**
 * Generated class for the FactorsPage page.
 *
 * See https://ionicframework.com/docs/components/#navigation for more info on
 * Ionic pages and navigation.
 */

@IonicPage()
@Component({
  selector: 'page-factors',
  templateUrl: 'factors.html',
})
export class FactorsPage {

  public results = {
    remaining: 0,
    total: 0
  }

  public preferences: any;
  public envFactors: any;
  public renderContent: Boolean = false;
  public userSelection: any;
  public userInput: any;
  public remainingResults: any;


  constructor(
    public navCtrl: NavController,
    public navParams: NavParams,
    public storage: LocalStorageProvider,
    public envCalculator: EnvCalculatorProvider) {

  }

  ionViewDidLoad() {
    // Get selected sport/activity from the user
    this.userSelection = this.storage.getUserData('selection');
    let allActivities: any = this.storage.getSportActivityFactors('sports');

    // sorts out the environment factors for the specific activity and stores them locally
    allActivities.forEach((activity) => {
      if (activity.name === this.userSelection) {
        this.envFactors = activity.envFactors;
      }
    })

    // DO NOT REMOVE
    // This is needed because there is a problem with ionic displaying segments dynamically
    setTimeout(() => {
      this.renderContent = true;
      this.preferences = this.envFactors[0].name;
    }, 100)

    this.calculate()
  }

  setFactors(factor) {
    let data = { name: factor, value: this.userInput };
    this.storage.setUserData('selectedFactors', data)
    this.calculate();
  }

  calculate() {
    this.envCalculator.calculate().then((x) => {
      this.results.remaining = x['remaining'];
      this.results.total = x['total'];
      this.remainingResults = x['results'];
    }).catch((err) => {
      console.log(err);
    })
  }

  /**
   * Userd to toggle each of the segment groups and reset the open factors.
   * If this isn't here then the open factor will not render on return
   *
   * @memberof FactorsPage
   */
  toggleGroup() {
    this.envFactors.forEach(activity => {
      activity.factors.forEach(factor => {
        factor.open = false;
      });
    });
  }

  /**
   * Used to toggle each of the factors
   *
   * @param {any} i
   * @param {any} ii
   * @memberof FactorsPage
   */
  toggleSection(i, ii) {
    this.envFactors[i].factors.forEach(element => {
      element.open = false;
    });
    this.envFactors[i].factors[ii].open = !this.envFactors[i].factors[ii].open
  }

  /**
   * Used to dynamically render all of the values in the range lists
   *
   * @param {any} type
   * @param {any} pos
   * @param {any} value
   * @returns
   * @memberof FactorsPage
   */
  getVal(type, pos, value) {
    if (pos == 'start') { return value[0]; }
    if (pos == 'end') { return value[value.length - 1] }
  }

  setRemainingResults() {

    let r = [];

    this.remainingResults.filter((dest) => {
        r.push({name: dest.name});
    })

    this.storage.setUserData('selectedResults', r)
  }

  goToNextPage() {

    // set remain results
    this.setRemainingResults();

    this.navCtrl.push('ResultsPage');
  }

}

The problem that I’m having is when a user selects a value on one of the elements then moves to another element then goes back, the first element has changed to what the second element value is. This is only visually for now because I’ve made it so when a user makes a change on the page the factors are calculated and the UI is updated, which it needs to be anyways.

Question: Does anyone know how to stop the other elements from changing when other elements on the page have changed?