4

I'm trying to achieve a cascade dropdown in Angular. I thought it would just work naturally thanks to binding. See below:

<select name="client" ng-model="selectedRequest.client" ng-options="c.name for c in clients track by c.id" required></select>
<select id="department" ng-model="selectedRequest.department" ng-options="d.defaultLabel for d in selectedRequest.client.departments track by d.id"></select>

When the view is loaded, it works, I can see the departments matching those bound to the client. However, whenever the selectedRequest.client changes, the source for the department dropdown should change too, but instead it becomes empty.

EDIT

I've changed the child dropdown to :

<select id="department" ng-model="selectedRequest.department" ng-options="d.defaultLabel for d in departments track by d.id | filter:{clientId: selectedRequest.client.id}"></select>

but this time it loads all the departments in the dropdown, ignoring the filter.

** EDIT 2 **

Changing to :

 <select name="client" ng-model="requestService.selectedRequest.client" ng-options="c as c.name for c in clients track by c.id" required></select>

 <select id="department" ng-model="requestService.selectedRequest.department" ng-options="d.defaultLabel for d in departments  | filter:{clientId: requestService.selectedRequest.client.id}"></select>

Now the source changes correctly when a client is selected. However the initial selection, i.e setting the right department at startup, does not work. That's because I've removed the 'track by id' bit.

6
  • This seems to be fine. You would need to create a fiddle and repo this issue. Maybe the dept is empty. Commented Oct 11, 2013 at 9:39
  • I've edited my post with a new approach Commented Oct 11, 2013 at 9:56
  • What happens if you remove the "track by" from ng-options? Commented Oct 11, 2013 at 10:08
  • If I do that, it works. But then the binding is lost, i.e the selected value is not set. Commented Oct 11, 2013 at 12:01
  • what you could do as a design, is instead of loading up two sources of data automatically when the page loads up, you can make a new request to fetch departments whenever the city dropdown is selected. refer to this jsfiddle to prove the point of $watch Commented Jan 27, 2014 at 15:58

2 Answers 2

4

the correct way was

 <select id="department" ng-model="selectedRequest.department" ng-options="d.defaultLabel for d in departments | filter:{clientId: selectedRequest.client.id} track by d.id "></select>

it's just that I hadn't put the filter at the right place... silly mistake.

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

1 Comment

Track by is treated like a filter. I just had the same issue and this solved it ! Thx
3

It could be that your selectedRequest.client does not refer to the same object in clients array. Try this:

JS:

function testController($scope) {
            $scope.clients = [
             { id: 1, name: "client1", departments: [{ id: 1, defaultLabel: 'department1' }, { id: 2, defaultLabel: 'department2'}] },
             { id: 2, name: "client2", departments: [{ id: 3, defaultLabel: 'department3' }, { id: 4, defaultLabel: 'department4'}] }
            ];

             $scope.selectedRequest = {};
             $scope.selectedRequest.client = $scope.clients[0];//Assign by object reference.
        }

HTML:

<div ng-controller="testController">
        <select name="client" ng-model="selectedRequest.client" ng-options="c.name for c in clients" required></select>
        <select id="department" ng-model="selectedRequest.department" ng-options="d.defaultLabel for d in selectedRequest.client.departments"></select>
    </div>

DEMO

I removed track by to use the default (track by object reference) and ensure that selectedRequest.client refers to objects inside clients

5 Comments

I don't see what you've changed other than removing the 'track by id' and setting the source to the first object in the array. My issue is that the departments are not filtered. Actually I managed to get it work by removing 'track by id' from the Departments ng-options. However now, the value is not set at startup (but the source changes correctly when a client is selected)
@Sam: could you give more code in your question? How did you initialize your scope object?
@Sam: However now, the value is not set at startup. I don't know if this is what you want jsfiddle.net/6eCZC/3
That's what I want. But the reason it works for you is because you are setting the selected value to the first object in the array. In my case, the selected value is an object that does not come from the source array. So it is not equal to any objects in the array - That's why I use 'track by id'
@Sam: I don't know if it's possible for you to find an object in the source array based on the selected value (id in your case) when you initialize your scope object.

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.