0

I have this working jsfiddle: working fiddle for second level

where I assign a brand from first dropdown and a model from second dropdown to each car created from ng-repeat. This works fine.

But I have to add the third level (type) as shown in this not working jsfiddle: not working fiddle for third level

I know where the problem is, but I have no idea how to repair it. This is undefined:

$scope.cars[index].model.model

Any suggestions?

Thank you.

2
  • It's not clear how the types should work. Does the type depend on the selected model? Could you make an example of a type? Commented May 4, 2016 at 18:53
  • Yes the type depends on the model. E.g. AUDI(brand), TT COUPE(model), COUPE (type). Commented May 4, 2016 at 19:12

3 Answers 3

0

The way you formatted your JSON object is hard to read and not intuitive. I suggest formatting it in such a way that you can get to the car selection easily by going cars.brands[0].models[0].types[0]. That way, you can make use of ng-options without much effort. See working Fiddle: https://jsfiddle.net/udr9dksa/1/

var app = angular.module("app", []);
app.controller("MainCtrl", ["$scope",
    function($scope) {
    
    	$scope.selectedBrand = {};
        $scope.selectedModel = {};
        $scope.selectedType = {};
        
        $scope.cars = {
            brands: [{
                id: 1,
                name: "audi",
                models: [{
                    id: 1,
                    name: 'audiA',
                    types: [{
                        id: 1,
                        name: 'type audi A1'
                    }, {
                        id: 2,
                        name: 'type audi A2'
                    }]
                }, {
                    id: 2,
                    name: 'audiB',
                    types: [{
                        id: 1,
                        name: 'type audi B1'
                    }, {
                        id: 2,
                        name: 'type audi B2'
                    }]
                }]
            }, {
                id: 2,
                name: "bmw",
                models: [{
                    id: 1,
                    name: 'bmwA',
                    types: [{
                        id: 1,
                        name: 'type bmw A1'
                    }, {
                        id: 2,
                        name: 'type bmw A2'
                    }]
                }, {
                    id: 1,
                    name: 'bmwB',
                    types: [{
                        id: 1,
                        name: 'type bmw B1'
                    }, {
                        id: 2,
                        name: 'type bmw B2'
                    }]
                }]
            }]
        };
    }
]);
<div ng-app="app" ng-controller="MainCtrl">
  <h4>Select a brand</h4>
  <select ng-model="selectedBrand" ng-options="brand as brand.name for brand in cars.brands">
  </select>
  
  <h4>Select a model</h4>
  <select ng-model="selectedModel" ng-options="model as model.name for model in selectedBrand.models">
  </select>
  
  <h4>Select a type</h4>
  <select ng-model="selectedType" ng-options="type as type.name for type in selectedModel.types">
  </select>
  
  <h3>You have selected</h3>
  <pre>{{selectedType | json}}</pre>
  
</div>

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>

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

4 Comments

I know, but I obtain the data from the database, so in this example I've used the JSON to simulate the database organization.
You can easily reformat your JSON object inside javascript or in the backend.
I can, but the database is extremely huge. Now, I inject only cars (car 1, car 2 etc) then on selected option only its model, and then on selected option its type...The JSON containing whole DB will be extreme, isn't it?
So then you'd have to re-think your UI and your workflow. Perhaps you can GET brands/models/types piecemeal. When the UI initially loads, have the user select a brand, from brand, get a list of models by feeding parameter brand, and so on.
0

I would change your data structure a bit so you don't have to do anything with a ng-change handler.

Add eveything to brands model then you can easily work with ng-options. If you're working with Mongoose and MongoDB you could use embedded documents for the models and probably normalized data for the type (only store the index from the types collection). (In the demo everything is embedded into brands to keep the demo easier to understand.)

Please have a look at the demo below or thid fiddle.

angular.module('demoApp', [])
  .controller('mainController', MainController);

function MainController($window) {
  var vm = this;
  vm.show = function(car) {
    if (!car.brand || !car.model || !car.type) return; // all fields required

    $window.alert('Selected brand ' + car.brand.name + ' - model: ' +
      car.model.name + ' - type: ' + car.type.name);
  };
  vm.cars = [{
    id: 0,
    name: 'car 1'
  }, {
    id: 1,
    name: 'car 2'
  }, {
    id: 2,
    name: 'car 3'
  }];

  vm.brands = [{
    id: 0,
    name: 'Audi',
    models: [{
      id: 0,
      name: 'Audi 1',
      types: [{
        id: 0,
        name: 'cabrio'
      }, {
        id: 1,
        name: 'combi'
      }]
    }, {
      id: 1,
      name: 'Audi 2',
      types: [{
        id: 0,
        name: 'limosine'
      }, {
        id: 1,
        name: 'van'
      }]
    }, {
      id: 2,
      name: 'Audi 3',
      types: [{
        id: 0,
        name: 'mini van'
      }, {
        id: 1,
        name: 'combi'
      }]
    }]
  }, {
    id: 1,
    name: 'BMW',
    models: [{
      id: 0,
      name: 'BMW 1',
      types: [{
        id: 0,
        name: 'cabrio'
      }, {
        id: 1,
        name: 'combi'
      }]
    }, {
      id: 1,
      name: 'BMW 2',
      types: [{
        id: 0,
        name: 'limosine'
      }, {
        id: 1,
        name: 'van'
      }]
    }, {
      id: 2,
      name: 'BMW 3',
      types: [{
        id: 0,
        name: 'mini van'
      }, {
        id: 1,
        name: 'combi'
      }]
    }]
  }];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="mainController as mainCtrl">
  <div ng-repeat="car in mainCtrl.cars">
    {{car.name}}
    <label>brand</label>
    <select ng-model="car.brand" ng-options="brand as brand.name for brand in mainCtrl.brands">
    </select>
    <label>model</label>
    <select ng-model="car.model" ng-options="model as model.name for model in car.brand.models">
    </select>
    <label>type</label>
    <select ng-model="car.type" ng-options="type as type.name for type in car.model.types">
    </select>
    <button ng-click="mainCtrl.show(car)">
      show
    </button>
  </div>

  <h2>
    current cars model (debugging):
    </h2>
  <pre>
        {{mainCtrl.cars | json : 2}}
    </pre>
</div>

Comments

0

Without change your data structure need change DOM and your functions to working perfect.

change only your second and third one select tag. for second one ng-change function calling. like: ng-change="loadTypes($index, brand.model.model)". For third one use cars[$index].models[$index].types instead of cars[$index].models.types means assign in specific models array and related change your controller functions.

can try like:

HTML:

<label>model</label>
    <select ng-model="brand.model" ng-options="caras car.model for car in cars[$index].models"  ng-change="loadTypes($index, brand.model.model)"><option value="">select</option></select>

<label>type</label>
    <select ng-model="car.brand.model.type" ng-options="car as car.type for car in cars[$index].models[$index].types"><option value="">select</option></select>

and your function should like:

$scope.loadModels = function(index){
    $scope.cars[index].models = $scope[$scope.cars[index].brand.name];
}
$scope.loadTypes = function(index, brandModel){
    $scope.cars[index].models[index].types = $scope[brandModel];
}

2 Comments

Thank you, but there is still problem. If you select same brand that was selected before, the third dropdown is re-chaged by the new value of the last brand...
Updated my answer should be working fine. :) @user3700786

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.