0

I am trying to bind data from a web service and then use that data to pre-populate a form. All form controls are binding correctly except for a single multi-select element. If I manually select an option the model does update. Below is my controller:

myApp.controller('AdminVideosEditCtrl', [
    '$scope',
    '$http',
    '$routeParams',
    '$location',
    function($scope, $http, $routeParams, $location) {
        $http.get('/videos/' + $routeParams.videoId + '?embed=presenters').success(function(data) {
            $scope.video = data.data
            // Load providers
            $http.get('/providers').success(function(data) {
                $scope.providers = data.data;
                // Load Presenters
                $http.get('/presenters').success(function(data) {
                    $scope.presenters = data.data;
                });
            });
        });
    }
]);

Once the final request returns, my model looks like this (output via {{ video | json }}):

{   
    "id": "ca3ca05a-834e-47b1-aaa1-3dbe38338ca9",   
    "title": "Doloremque iure consequatur quam ea.",   
    "is_public": false,   
    "is_visible": true,   
    "url": "http://someurl.com/",   
    "provider_id": "1b4d18eb-d56c-41ae-9431-4c058a32d651",   
    "level_id": "38ed7286-da05-44b9-bfb9-e1278088d229",   
    "duration": "17:38",   
    "transcript_file": "rerum-sint-voluptatum.md",   
    "presenters": [
        {
            "id": "5111531d-5f2a-45f5-a0c4-4fa3027ff249",
            "first_name": "First",
            "last_name": "Last",
            "full_name": "First Last"
        }   
    ],   
    "provider": {
        "id": "1b4d18eb-d56c-41ae-9431-4c058a32d651",
        "title": "You Tube"   
    } 
}

Here is how the multi-select looks in my view:

<div class="form-group">
    <label for="presenters" class="col-lg-2 control-label">Presenters</label>
    <div class="col-lg-10">
        <select multiple="multiple" class="form-control" id="presenters" ng-model="video.presenters" ng-options="presenter.full_name for ( id , presenter ) in presenters">
        </select>
    </div>
</div>

The select element populates correctly, and I would expect for it to default with the "First Last" element selected, however nothing is selected. I know my model is initialized correctly because if I manually select the element nothing in the model changes (if I select a different element it does, but still retains the same structure as it does on initial page load).

I tried adding a $scope.$apply call, and I also tried $scope.$root.$eval(), neither of which worked.

Update

The presenters model (containing all of the presenters) looks like this after it is fetched from the service (names have been changed to protect the innocent):

[
  {
    "id": "47b6e945-2d4b-44c2-b44b-adb96460864d",
    "first_name": "First",
    "last_name": "Last",
    "full_name": "First Last"
  },
  {
    "id": "5111531d-5f2a-45f5-a0c4-4fa3027ff249",
    "first_name": "One",
    "last_name": "Two",
    "full_name": "One Two"
  },
  {
    "id": "7cb1e44b-2806-4576-80b2-ae730ad356f7",
    "first_name": "Three",
    "last_name": "Four",
    "full_name": "Three Four"
  }
]
5
  • I set up a fiddle for you jsfiddle.net/dcodesmith/ej7Cv. nothing seems to be coming up in the select box. Are you sure you get any data in there? Commented Jan 22, 2014 at 16:18
  • @dcodesmith yes, the presenters are actually loaded from the third $http call (and live in $scope.presenters, not $scope.video.presenters, those are the ones that are selected for the video) Commented Jan 22, 2014 at 16:26
  • Could you please update the fiddle to show it works, I've done half that for you already Commented Jan 22, 2014 at 16:28
  • fiddle updated: jsfiddle.net/ej7Cv/3 Commented Jan 22, 2014 at 16:29
  • link please, the link should be different now Commented Jan 22, 2014 at 16:30

1 Answer 1

2

Solution

Just put this at the bottom of your controller

$scope.video.presenters.forEach(function(obj, idx){
    $scope.presenters.forEach(function(presenter, jdx){
        if (obj.id === presenter.id) {
            $scope.video.presenters = [$scope.presenters[jdx]]
        }
    });
});

JSFIDDLE

More Robust Solution

This is more robust as you might want to preselect multiple options. This solution pushes each selected option into an array and then assigns it to $scope.video.presenters model

    var selectedOptions = [];

    $scope.video.presenters.forEach(function (obj, idx) {
    $scope.presenters.forEach(function (presenter, idj) {
        if (obj.id === presenter.id) {
            selectedOptions.push($scope.presenters[idj]);
            $scope.video.presenters = selectedOptions;
        }
    });

JSFIDDLE

Note: Ideally you should be using the id key as the unique for the objects. This solution assumes and only caters for preselecting one option.

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

4 Comments

without doing some kind of deferring, I don't think this will work since the ng-init will execute prior to my service call containing the presenters returns
Not sure this works, check: jsfiddle.net/ej7Cv/9 I've changed the initial presenter to be the second entry, but the first one is the one that gets selected.
nevermind, I figured out the minor issue.. needed a second index parameter into the second foreach. The unique identifier is the id parameter
also, changing the assignment to a push also supports multiple presenters, +1 and thanks for the help!

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.