Will Strohl
Will Strohl

Reputation: 1680

Unable to bind model to template

I'm attempting to build a directive to handle the rendering of a repeating list of speakers. The end goal here is to have the page automatically reflect the updates made in a modal.

The problem I'm appearing to see here is that the speakers object doesn't appear to make it into the template.

This is the function that populates speakers. It's called in the modal's promise. speakers is a collection of speaker objects. The data comes back as expected.

$scope.updateSpeakersList = function () {
    factory.callGetService("GetSpeakers?eventId=" + $scope.event.eventId)
        .then(function (response) {
            var fullResult = angular.fromJson(response);
            var serviceResponse = JSON.parse(fullResult.data);

            $scope.speakers = serviceResponse.Content;

            if ($scope.speakers === null) {
                $scope.hasSpeakers = false;
            } else {
                $scope.hasSpeakers = ($scope.speakers.length > 0);
            }

            LogErrors(serviceResponse.Errors);
        },
        function (data) {
            console.log("Unknown error occurred calling GetSpeakers");
            console.log(data);
        });
}

// other code... then this

modalInstance.result.then(function (savedSpeaker) {
    console.log("BEGIN modalInstance.result");
    $scope.savedSpeaker = savedSpeaker;
    console.log("$scope.savedSpeaker = " + $scope.savedSpeaker);

    $scope.updateSpeakersList();
    console.log("END modalInstance.result");
}, function () {
    console.log("Modal dismissed at: " + new Date());
});

The HTML looks like this.

<div class="container" ng-show="hasSpeakers">
    <div class="row">
        <speaker-cards data="speakers"></speaker-cards>
    </div>
</div>

The directive is pretty simple.

.directive("speakerCards", function() {
    return {
        restrict: "E",
        templateUrl: "/Apps/Event/Templates/_default/speaker-cards.html",
        scope: {
            data: "="
        }
    };
});

The "speaker cards" template is a bit more complex than this, but you should get the point.

<!-- BEGIN speaker cards -->
<div ng-repeat="speaker in speakers | orderBy: 'SpeakerName'">
    <div class="clearfix" ng-if="$index % 3 == 0"></div>
    <div class="col-sm-4">
        <div class="card">
            <span class="speaker-name">{{speaker.SpeakerName}}</span><br/>
            <span class="speaker-title">{{speaker.CompanyTitle}}</span><br/>
            <span class="speaker-company">{{speaker.CompanyName}}</span>
        </div>
    </div>
</div>
<!-- END speaker cards -->

Besides the speakers not appearing, the reason I don't think that speakers is making it into the template, is because the resulting markup looks like this.

enter image description here

Upvotes: 1

Views: 65

Answers (2)

Arkantos
Arkantos

Reputation: 6608

The issue in your code is in the scope definition of your custom directive.

scope: {
        data: "="
       }

With this, it will look for a data attribute on your directive like <speaker-cards data='speakers'> and assigns it to data property on the isolated scope created for this directive.

But you're looking for speakers in your template.

<div ng-repeat="speaker in speakers | orderBy: 'SpeakerName'">

But there's no speakers defined in your current directive scope, there's only data property, so you can fix it by changing your template like below.

<div ng-repeat="speaker in data | orderBy: 'SpeakerName'">

You can also fix this by changing your scope definition to capture data attribute from directive as speakers in your directive scope.

myApp.directive("speakerCards", function() {
    return {
        restrict: "E",
        templateUrl: "template.html",
      scope: {
            speakers: "=data"
        }
    };
});

With this, you don't have to change your template. Here's a sample Pen to illustrate this.

Upvotes: 5

ThiagoPXP
ThiagoPXP

Reputation: 5462

Are you defining your var $scope.speakers when the Angular Ctrl first run?

If you only define speakers at later stage eg: when the function updateSpeakersList returns with data, Angular might not have configured speakers and might have no watchers in it (due to how dependency injection works in AngularJs).

Add the following line when the angular controller first run (configuration time)

$scope.speakers = [];

Upvotes: 1

Related Questions