1

Угловой новичок Вопрос:Почему директива AngularJS работает с жестко закодированными значениями, но не работает с запросом/ответом HTTP?

У меня есть простая тестовая программа AngularJS, которая показывает, как контроллер и директива работают вместе. Контроллер устанавливает некоторые жестко закодированные значения aB и aC на область действия, и директива затем отображает эти значения в HTML. Оно работает. Вот JSFiddle. Код ниже. Когда вы запустите ее, вы можете увидеть выход консоли, как и ожидалось:

JS line #63: this.aB = null 
JS line #64: this.aC = Goodbye 
JS line #63: this.aB = Hello 
JS line #63: this.aC = World 

Однако, когда я изменить жёстко прописанные значения на те, которые извлекаются из тестового API, он терпит неудачу. Выход консоли выглядит следующим образом:

JS line #63: this.aB = null 
JS line #64: this.aC = Goodbye 
JS line #63: this.aB = undefined 
JS line #63: this.aC = undefined 

Единственное изменение, которое я сделал (видел здесь, в этом новом JSFiddle) был в myFunc функции контроллера: я заменил жестко закодированные значения со следующим:

response = $http.post('http://jsonplaceholder.typicode.com/posts', 
    { 
     'XXXXX': 'YYYYYYY' 
    } 
)  
    self.scopeAB = response.id; 
    self.scopeAC = response.id; 

Я протестировал ответ API через curl, и он работает нормально. Так почему же директива сообщает значения aB и aC как undefined? Как решить эту проблему? Я могу сказать, что это связано с асинхронным характером HTTP-вызова. Но я не знаю, как правильно сделать эту работу.

HTML:

<body ng-app="myApp"> 
    <div ng-controller="MyCtrl as ctrl"> 
    <div ng-view></div> 
    <ul> 
     <li>{{1+1}}</li> 
     <li><my-directive a-b="null" a-c="'Goodbye'"></my-directive></li> 
     <li><my-directive a-b="ctrl.scopeAB" a-c="ctrl.scopeAC"></my-directive></li> 
     ab = {{ctrl.scopeAB}}, ac = {{ctrl.scopeAC}} 
    </ul> 
    </div> 
</body> 

Рабочий Javascript:

myApp = angular.module('myApp',[]); 
myApp.directive('myDirective',function(){ 
    return { 
     restrict:'E', 
     scope: { 
     aB: '=', 
     aC: '=' 
     }, 
     controller: 'DirectiveCtrl', 
     controllerAs: 'dirCtrl', 
     bindToController: true, 
     template: 'aB={{dirCtrl.aB}} aC={{dirCtrl.aC}} <input ng-model="dirCtrl.aB" />' 
    }; 
    } 
); 

myApp.controller('DirectiveCtrl', function(){ 
    var self = this; 
    console.log('this.aB = ', self.aB); 
    console.log('this.aC = ', self.aC); 
}) 

myApp.controller('MyCtrl', function() { 
    var self = this; 
    self.myFunc = function() { 
     self.scopeAB = 'Hello'; 
     self.scopeAC = 'World'; 
    }(); 
    } 
); 

UPDATE: Claies предложил мне использовать эту JSFiddle. Но это не сработает для меня, потому что мне абсолютно необходимы значения aB и aC, которые будут доступны в контроллере директивы. Мне нужно изменить шаблон на основе их значений. Этот JS Fiddle, кажется, показывает им, как всегда, неопределенный там.

+0

проблема здесь - еще одна часть углового, которая требует немного объяснения. Я прыгнул обратно в чат-канал AngularJS http://chat.stackoverflow.com/rooms/63378/angularjs, если вы хотите обсудить, что происходит, и возможные способы борьбы с ним. – Claies

+0

Ответ здесь отвечает на вопрос, почему значения контроллера не обновляются с помощью '$ http', но это не вся картина. Что касается того, почему директива не обновляется, когда контроллер делает это, это другая тема, в которой я чувствую, что, возможно, частично вы сбились с пути при обсуждении этой темы в более ранних вопросах. – Claies

+0

Я обновил вопрос на основе нашего последнего чата. Но проблема остается. –

ответ

1

Claies предложил мне использовать этот JSFiddle. Но это не сработает для меня, потому что мне абсолютно необходимы значения aB и aC для доступа к контроллеру директивы. Мне нужно изменить шаблон на основе их значений. Этот JS Fiddle, кажется, показывает им, как всегда, неопределенный там.

Если вы используете @Claies методологии, вам нужно поставить $watch на объект, который срабатывает, когда $http запрос рассасывается.

myApp.controller('DirectiveCtrl', function($scope){ 
    var self = this; 
    $scope.$watch(function() {return self.scopeObject}, function (objVal) { 
     console.log("watch fired"); 
     console.log('objVal.aB = ', objVal.aB); 
     console.log('objVal.aC = ', objVal.aC);  
    },true); 

}); 

DEMO on JSFiddle.

Честно говоря, я думаю, что вам лучше следовать совету от @jumbopap.Используйте метод httpPromise и .then и извлеките данные из функции onFulfilled.

+0

@jumbopap был упомянут в этом ответе. – georgeawg

+0

В этом ответе упоминалось @claies. – georgeawg

+0

georgeawg Я хотел бы использовать ответ @ jumbopap, но я не совсем понимаю его, потому что он не показал, что JSFiddle полностью работает. –

2

Вы должны прочитать документы на $http service. Вызов асинхронно, и вы справляетесь успешный ответ на then обратного вызова

$http.post('http://jsonplaceholder.typicode.com/posts', {'XXXXX': 'YYYYYYY'}) 
    .then(function(response) { 
     self.scopeAB = response.data.id; 
     self.scopeAC = response.data.id; 
    }) 
+0

Это дает тот же выход консоли: https://jsfiddle.net/saqibali75/8maswfqb/1/ –

+1

Ответ * в основном * правильный, но при использовании '.then' ответ немного отличается. Я обновил ответ, 'response.data.id' будет правильным использованием. Тем не менее, это все еще не составляет 100% -ного смысла, так как этот код фактически сделает 'scopeAB' и' scopeAC' равными одному и тому же значению, что довольно странно. – Claies

+0

Проверьте, что говорит консоль: 'Смешанное содержимое: страница на странице https://fiddle.jshell.net/saqibali75/8maswfqb/1/show/ была загружена через HTTPS, но запросила небезопасную конечную точку XMLHttpRequest 'http://jsonplaceholder.typicode.com/posts. Этот запрос заблокирован; содержимое должно быть передано через HTTPS. «Загрузите страницу без https. – jumbopap