$watch не читает объект

На моем сайте есть плеер, который показывает, какую песню я сейчас слушаю. Однако, чтобы обновить отображаемую песню, мне пришлось обновить страницу.

На данный момент я хочу, чтобы код проверял внешний файл json. Он должен проверить название песни и при обнаружении изменения обновить проигрыватель на веб-сайте.

К сожалению, здесь я натыкаюсь на блокпост.

Сначала я попытался использовать функцию $interval, хотя она и работала, она обновляла <div>, как обновление страницы.

Я попробовал функцию scope.$watch, но она не работает. Похоже, $watch срабатывает только один раз при загрузке страницы. Это может быть связано с тем, что область действия не является слушателем. Однако, когда я пытаюсь добавить прослушиватель, мне нужно изменить модуль, так как это директива...

angular.module('lastfm-nowplaying', [])
    .directive('lastfmnowplaying', ['uiCreation', 'lastFmAPI', 'lastFmParser', '$http', function (uiCreation, lastFmAPI, lastFmParser, $http) {
        var link = function (scope, element, attrs) {

            $http({
                method: 'GET',
                url: 'https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=--NAME--&api_key=--API--&format=json&limit=1'
            }).then(function (songdata) {
                var currentsongs = songdata.data.recenttracks.track[0].name;
                console.log(songdata);
                console.log(currentsongs);
            }, function (error) {
                //oopsie
            });

            scope.$watch('currentsongs', function (value) {
                load(value);
                console.log("Change detected");
            }, true);

            var load = function () {
                var latestTrack;

                if (scope.config) {

                    if (scope.config.apiKey) {

                        lastFmAPI.getLatestScrobbles(scope.config).then(function (data) {

                            latestTrack = lastFmParser.getLatestTrack(data);
                            angular.element(element).addClass('lastfm-nowplaying');
                            uiCreation.create(element[0], scope.config.containerClass, latestTrack);
                        }, function (reason) {
                            //Last.fm failure
                        });
                    } else {
                        var latestTrack = {
                            title: scope.config.title,
                            artist: scope.config.artist,
                            largeImgUrl: scope.config.imgUrl,
                            xLargeImgUrl: scope.config.backgroundImgUrl,
                        }
                        angular.element(element).addClass('lastfm-nowplaying');
                        uiCreation.create(element[0], scope.config.containerClass, latestTrack);
                    }

                }
            }


        };

        return {
            scope: {
                config: '=config'
            },
            link: link
        };
  }])

HTML

<body ng-app="app" ng-controller="mainCtrl">
    <div lastfmnowplaying config="lastFmConfig"></div>
</body>

Итак, через консоль я могу вызвать файл json и получить название песни, но я не могу обновить проигрыватель с помощью scope.$watch, он срабатывает только один раз (?)

Я знаю только основы Angular, и поэтому я не смогу решить это самостоятельно в ближайшее время.


person Niels    schedule 04.08.2019    source источник
comment
В вашем предыдущем вопросе наблюдатель просматривал переменную области, которая была связана с привязкой атрибута к переменной родительского контроллера. Теперь наблюдатель наблюдает за переменной локальной области видимости, и я не вижу кода, присваивающего что-либо этой переменной.   -  person georgeawg    schedule 04.08.2019
comment
Привет, я создал codepen. Может быть, это дает вам четкое представление о том, что происходит. Как уже говорилось, я совершенно новичок в angular, и у меня такое чувство, что я очень близок к ее решению, но, к сожалению, я не могу сделать это самостоятельно.   -  person Niels    schedule 04.08.2019
comment
Код неудобно факторизован. Директива должна просто отображать информацию о дорожке, которую указывает контроллер. Главный контроллер должен опрашивать API и обновлять указанную дорожку, когда название песни отличается от предыдущего имени.   -  person georgeawg    schedule 05.08.2019
comment
Да, вы совершенно правы! Это не совсем мой код, поэтому я (пытаюсь) настроить его по своему вкусу. Я просто понятия не имею, что лучший вариант - автоматически обновлять трек. Я не ожидаю, что вы внезапно придумаете полностью работающий код (хотя, черт возьми, это было бы здорово!). Есть советы/наводки?   -  person Niels    schedule 05.08.2019


Ответы (2)


Вот главный контроллер, который опрашивает API каждые 6 секунд:

app.controller("mainCtrl", function($scope, $interval, service) {
    service.getLastTrack.then(function (track) {
        $scope.latestTrack = track;
    });
    $interval(getNextTrack, 6000);

    function getNextTrack() {
        service.getLastTrack.then(function (track) {
            if ($scope.latestTrack.name != track.name) {
                $scope.latestTrack = track;
            };
        });
    }
})

Применение:

<body ng-app="app" ng-controller="mainCtrl">
    <div lastfmnowplaying config="latestTrack"></div>
</body>

Это пример того, как опросить API и обновить конфигурацию директивы при изменении свойства данных.

Для получения дополнительной информации см.

person georgeawg    schedule 04.08.2019
comment
Привет, Джордж! Большое спасибо за помощь! Я пытался подогнать код под вашу модель, но поскольку он, как вы сказали, неуклюже разложен, я не могу его решить, не попадая в новую волну ошибок. У меня была другая идея, которую я сейчас проверяю. Я оставил это как комментарий под ответом bryan60. - person Niels; 05.08.2019

причина, по которой часы не работают, заключается в том, что currentsongs не является переменной области действия директивы. он ограничен вашим обработчиком http. сделайте это вместо этого:

        scope.currentsongs = '';

        // start watching prior to http call just in case?
        scope.$watch('currentsongs', function (value) {
            load(value);
            console.log("Change detected");
        }, true);

        $http({
            method: 'GET',
            url: 'https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=--NAME--&api_key=--API--&format=json&limit=1'
        }).then(function (songdata) {
            scope.currentsongs = songdata.data.recenttracks.track[0].name;
            console.log(songdata);
            console.log(scope.currentsongs);
        }, function (error) {
            //oopsie
        });
person bryan60    schedule 04.08.2019
comment
Привет, Брайан, большое спасибо за предложенный код. К сожалению, похоже, он не работает. Я получаю reference error: currentsong is not defined. Может быть, вы могли бы разветвить мою codepen и внести в нее какое-нибудь предложение? Я думал попробовать оператор if, который читает название текущей песни и последней песни, если они отличаются, песня будет обновляться. Это делается с помощью $interval. - person Niels; 05.08.2019
comment
это была ошибка в вашем заявлении о регистрации, код обновлен - person bryan60; 05.08.2019
comment
Благодарить! На этот раз ошибок нет :D Однако console.log(обнаружено изменение); стреляет только один раз. Это означает, что scope.$watch не обновляется при обнаружении изменения (?). Есть предположения, почему это происходит? (обновил codepen) - person Niels; 05.08.2019