1

My first AngularJS App...

http://plnkr.co/edit/KJoGFWjrAwHHPOZkHxAV?p=preview

I'm trying to achieve the following functionality:

  1. Select either 'Solo Artist' or 'Band' from select box 1
  2. Once that selection has been made, the following should appear in select box 2:

    • 'Solo Artist' -> One Song (Vocal And Instrument) or One Song (Vocal To Pre-Recorded Backing Track)
    • 'Band' -> EP or One Song
  3. Once that selection has been made, the following number of options should appear in select box 3:

    • 'Solo Artist' -> 'One Song (Vocal And Instrument)': 3
    • 'Solo Artist' -> 'One Song (Vocal To Pre-Recorded Backing Track)': 13
    • 'Band' -> 'One Song': 2
    • 'Band' -> 'EP': 1

So far I have everything working up to step 2. However, looping over postsFiltered the second time seems to break everything. The array seems to get filtered twice in one digest (see console log in Plunker), removing all of its contents. The contents of the select boxes also gets mixed up; moving focus to select box 3 removes select box 2's content.

My questions:

  1. Is this the best way to go about doing something like this anyway (i.e. cloning an array and filtering it based on matches until there is only one object left in it)?
  2. Should I be using multiple arrays instead (i.e. creating an array for each step of the process? Is using one array robust enough, or should I be taking a different approach?
  3. At the moment, select box 3 gets populated along with select box 2 after a selection has been made from select box 1 and I'm not sure why. What do I need to do so they get populated sequentially instead? I'll be hiding select boxes before they're required, but would still like nice clean code all the same.

data.json

[{
    "postId": 1094,
    "postSlug": "band-ep-1-hour",
    "postTitle": "Band: EP – 1 Hour",
    "postTitleName": "Band",
    "postTitleItem": "EP",
    "postTitleTime": "1 Hour"
}, {
    "postId": 1093,
    "postSlug": "band-one-song-2-hours",
    "postTitle": "Band: One Song – 2 Hours",
    "postTitleName": "Band",
    "postTitleItem": "One Song",
    "postTitleTime": "2 Hours"
}, {
    "postId": 1092,
    "postSlug": "band-one-song-1-hour",
    "postTitle": "Band: One Song – 1 Hour",
    "postTitleName": "Band",
    "postTitleItem": "One Song",
    "postTitleTime": "1 Hour"
}, {
    "postId": 1076,
    "postSlug": "solo-artist-one-song-vocal-and-instrument-3-hours",
    "postTitle": "Solo Artist: One Song (Vocal And Instrument) – 3 Hours",
    "postTitleName": "Solo Artist",
    "postTitleItem": "One Song (Vocal And Instrument)",
    "postTitleTime": "3 Hours"
}, {
    "postId": 1071,
    "postSlug": "solo-artist-one-song-vocal-and-instrument-2-hours",
    "postTitle": "Solo Artist: One Song (Vocal And Instrument) – 2 Hours",
    "postTitleName": "Solo Artist",
    "postTitleItem": "One Song (Vocal And Instrument)",
    "postTitleTime": "2 Hours"
}, {
    "postId": 1069,
    "postSlug": "solo-artist-one-song-vocal-and-instrument-1-hour",
    "postTitle": "Solo Artist: One Song (Vocal And Instrument) – 1 Hour",
    "postTitleName": "Solo Artist",
    "postTitleItem": "One Song (Vocal And Instrument)",
    "postTitleTime": "1 Hour"
}, {
    "postId": 1066,
    "postSlug": "solo-artist-one-song-vocal-to-pre-recorded-backing-track-320-hours-40-days",
    "postTitle": "Solo Artist: One Song (Vocal To Pre-Recorded Backing Track) – 320 Hours (40 Days)",
    "postTitleName": "Solo Artist",
    "postTitleItem": "One Song (Vocal To Pre-Recorded Backing Track)",
    "postTitleTime": "320 Hours (40 Days)"
}, {
    "postId": 1065,
    "postSlug": "solo-artist-one-song-vocal-to-pre-recorded-backing-track-160-hours-20-days",
    "postTitle": "Solo Artist: One Song (Vocal To Pre-Recorded Backing Track) – 160 Hours (20 Days)",
    "postTitleName": "Solo Artist",
    "postTitleItem": "One Song (Vocal To Pre-Recorded Backing Track)",
    "postTitleTime": "160 Hours (20 Days)"
}, {
    "postId": 1064,
    "postSlug": "solo-artist-one-song-vocal-to-pre-recorded-backing-track-80-hours-10-days",
    "postTitle": "Solo Artist: One Song (Vocal To Pre-Recorded Backing Track) – 80 Hours (10 Days)",
    "postTitleName": "Solo Artist",
    "postTitleItem": "One Song (Vocal To Pre-Recorded Backing Track)",
    "postTitleTime": "80 Hours (10 Days)"
}, {
    "postId": 1063,
    "postSlug": "solo-artist-one-song-vocal-to-pre-recorded-backing-track-40-hours-5-days",
    "postTitle": "Solo Artist: One Song (Vocal To Pre-Recorded Backing Track) – 40 Hours (5 Days)",
    "postTitleName": "Solo Artist",
    "postTitleItem": "One Song (Vocal To Pre-Recorded Backing Track)",
    "postTitleTime": "40 Hours (5 Days)"
}, {
    "postId": 1062,
    "postSlug": "solo-artist-one-song-vocal-to-pre-recorded-backing-track-32-hours-4-days",
    "postTitle": "Solo Artist: One Song (Vocal To Pre-Recorded Backing Track) – 32 Hours (4 Days)",
    "postTitleName": "Solo Artist",
    "postTitleItem": "One Song (Vocal To Pre-Recorded Backing Track)",
    "postTitleTime": "32 Hours (4 Days)"
}, {
    "postId": 1061,
    "postSlug": "solo-artist-one-song-vocal-to-pre-recorded-backing-track-24-hours-3-days",
    "postTitle": "Solo Artist: One Song (Vocal To Pre-Recorded Backing Track) – 24 Hours (3 Days)",
    "postTitleName": "Solo Artist",
    "postTitleItem": "One Song (Vocal To Pre-Recorded Backing Track)",
    "postTitleTime": "24 Hours (3 Days)"
}, {
    "postId": 1060,
    "postSlug": "solo-artist-one-song-vocal-to-pre-recorded-backing-track-16-hours-2-days",
    "postTitle": "Solo Artist: One Song (Vocal To Pre-Recorded Backing Track) – 16 Hours (2 Days)",
    "postTitleName": "Solo Artist",
    "postTitleItem": "One Song (Vocal To Pre-Recorded Backing Track)",
    "postTitleTime": "16 Hours (2 Days)"
}, {
    "postId": 1059,
    "postSlug": "solo-artist-one-song-vocal-to-pre-recorded-backing-track-8-hours-1-day",
    "postTitle": "Solo Artist: One Song (Vocal To Pre-Recorded Backing Track) – 8 Hours (1 Day)",
    "postTitleName": "Solo Artist",
    "postTitleItem": "One Song (Vocal To Pre-Recorded Backing Track)",
    "postTitleTime": "8 Hours (1 Day)"
}, {
    "postId": 1057,
    "postSlug": "solo-artist-one-song-vocal-to-pre-recorded-backing-track-6-hours",
    "postTitle": "Solo Artist: One Song (Vocal To Pre-Recorded Backing Track) – 6 Hours",
    "postTitleName": "Solo Artist",
    "postTitleItem": "One Song (Vocal To Pre-Recorded Backing Track)",
    "postTitleTime": "6 Hours"
}, {
    "postId": 1056,
    "postSlug": "solo-artist-one-song-vocal-to-pre-recorded-backing-track-4-hours",
    "postTitle": "Solo Artist: One Song (Vocal To Pre-Recorded Backing Track) – 4 Hours",
    "postTitleName": "Solo Artist",
    "postTitleItem": "One Song (Vocal To Pre-Recorded Backing Track)",
    "postTitleTime": "4 Hours"
}, {
    "postId": 1055,
    "postSlug": "solo-artist-one-song-vocal-to-pre-recorded-backing-track-3-hours",
    "postTitle": "Solo Artist: One Song (Vocal To Pre-Recorded Backing Track) – 3 Hours",
    "postTitleName": "Solo Artist",
    "postTitleItem": "One Song (Vocal To Pre-Recorded Backing Track)",
    "postTitleTime": "3 Hours"
}, {
    "postId": 1053,
    "postSlug": "solo-artist-one-song-vocal-to-pre-recorded-backing-track-2-hours",
    "postTitle": "Solo Artist: One Song (Vocal To Pre-Recorded Backing Track) – 2 Hours",
    "postTitleName": "Solo Artist",
    "postTitleItem": "One Song (Vocal To Pre-Recorded Backing Track)",
    "postTitleTime": "2 Hours"
}, {
    "postId": 1043,
    "postSlug": "solo-artist-one-song-vocal-to-pre-recorded-backing-track-1-hour",
    "postTitle": "Solo Artist: One Song (Vocal To Pre-Recorded Backing Track) – 1 Hour",
    "postTitleName": "Solo Artist",
    "postTitleItem": "One Song (Vocal To Pre-Recorded Backing Track)",
    "postTitleTime": "1 Hour"
}]

basic HTML

<form>
    <fieldset id="app-contents-form-fieldset-1">
        <label for="entry-names">I want to record as a...</label>
        <select id="entry-names" ng-model="selected.name" ng-options="data.postTitleName as data.postTitleName for data in posts | unique:'postTitleName' track by data.postTitleName" ng-focus="selectedNameFocus()" ng-change="selectedNameChoice()">
            <option value="" default="" selected="selected">Please Choose...</option>
        </select>
    </fieldset>
    <fieldset id="app-contents-form-fieldset-2" ng-show="showFieldset2">
        <label for="entry-items">I want to record...</label>
        <select id="entry-items" ng-model="selected.item" ng-options="data.postTitleItem as data.postTitleItem for data in postsFiltered | unique:'postTitleItem' track by data.postTitleItem" ng-focus="selectedItemFocus()" ng-change="selectedItemChoice()">
            <option value="" default="" selected="">Please Choose...</option>
        </select>
    </fieldset>
    <fieldset id="app-contents-form-fieldset-3" ng-show="showFieldset3">
        <label for="entry-times">I want to spend this much time...</label>
        <select id="entry-times" ng-model="selected.time" ng-options="data.postTitleTime as data.postTitleTime for data in posts | unique:'postTitleTime' track by data.postTitleTime" ng-focus="selectedTimeFocus()" ng-change="doResult()">
            <option value="" default="" selected="">Please Choose...</option>
        </select>
    </fieldset>
</form>

app.js

var bookingStudioTime = angular.module('bookingStudioTime', ['angular.filter']);

bookingStudioTime.controller('mainController', ['$scope', '$http', '$filter', function($scope, $http, $filter) {

  $http.get('data.json').success(function(ret) {
      $scope.posts = ret;
  });

    $scope.selectedNameFocus = function() {
      $scope.showFieldset2 = true;
      $scope.showFieldset3 = true;
        $scope.postsFiltered = angular.copy($scope.posts);
    };

    $scope.selectedNameChoice = function() {
      $scope.showFieldset2 = true;
        for ( var i = $scope.postsFiltered.length - 1; i >= 0; i-- ) {
            if ( $scope.postsFiltered[i].postTitleName !== $scope.selected.name ) {
                $scope.postsFiltered.splice(i, 1);
                console.log($scope.postsFiltered);
            }
        }
        $scope.postsFilteredItems = $scope.postsFiltered;
    };

    $scope.selectedItemChoice = function() {
      $scope.showFieldset3 = true;
        for ( var i = $scope.postsFiltered.length - 1; i >= 0; i-- ) {
            if ( $scope.postsFiltered[i].postTitleItem !== $scope.selected.item ) {
                $scope.postsFiltered.splice(i, 1);
                console.log($scope.postsFiltered);
            }
        }
        $scope.postsFilteredItems = $scope.postsFiltered;
    };

    $scope.doResult = function() {

        for ( var i = $scope.postsFiltered.length - 1; i >= 0; i-- ) {
            if ( $scope.postsFiltered[i].postTitleTime !== $scope.selected.time ) {
                $scope.postsFiltered.splice(i, 1);
            }
        }

        $scope.selected.id = $scope.postsFiltered[0].postId;
        console.log($scope.selected.id);

    }

}]);

1 Answer 1

1

You can do this mostly in the markup, here's a plnkr

Form:

<form>
    <fieldset id="app-contents-form-fieldset-1">
        <label for="entry-names">I want to record as a...</label>
        <select id="entry-names" ng-model="selected.name" ng-options="data.postTitleName as data.postTitleName for data in posts | unique:'postTitleName' track by data.postTitleName" ng-focus="selectedNameFocus()" ng-change="selectedNameChoice()">
            <option value="" default="" selected="selected">Please Choose...</option>
        </select>
    </fieldset>
    <fieldset id="app-contents-form-fieldset-2" ng-show="selected.name">
        <label for="entry-items">I want to record...</label>
        <select id="entry-items" ng-model="selected.item" ng-options="data.postTitleItem as data.postTitleItem for data in posts | filter: {postTitleName: selected.name} | unique:'postTitleItem' track by data.postTitleItem" ng-focus="selectedItemFocus()" ng-change="selectedItemChoice()">
            <option value="" default="" selected="">Please Choose...</option>
        </select>
    </fieldset>
    <fieldset id="app-contents-form-fieldset-3" ng-show="selected.name && selected.item">
        <label for="entry-times">I want to spend this much time...</label>
        <select id="entry-times" ng-model="selected.time" ng-options="data.postTitleTime as data.postTitleTime for data in posts | filter: {postTitleName: selected.name, postTitleItem: selected.item} | unique:'postTitleTime' track by data.postTitleTime" ng-focus="selectedTimeFocus()" ng-change="doResult()">
            <option value="" default="" selected="">Please Choose...</option>
        </select>
    </fieldset>
</form>

List:

<ELEMENT ng-repeat="post in posts | filter: {postTitleName: selected.name, postTitleItem: selected.item, postTitleTime: selected.time}">

The only code left in the controller is to get the posts ($http)

You could probably also do without 'angular-filter' but if you're using it anyway, it's convenient.

Sign up to request clarification or add additional context in comments.

3 Comments

Perfect! This makes so much sense (and is so much cleaner besides!)... From a 'best-practice' point of view, what would you suggest be the best way of getting postId of the final selection? I'm leaning towards just creating a table as you did and hiding it from view, but I was wondering if it's 'cleaner' to loop through posts and get the ID based on selected matches? Many thanks for your help! :)
@GarethJames I've slightly modified the plnkr. See how ng-repeat is modified to add a scope variable "filteredPosts" which dynamically tracks the filtered Posts. Hope that helps.
That's great! The only addition I made was adding :true to the time filter... This ensured only exact matches were made, as 24 Hours (3 Days) was also displaying as a match for 4 Hours...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.