AngularJS: файл фабрики $ http.get JSON

84

Я ищу локальную разработку, используя только жестко закодированный файл JSON. Мой файл JSON выглядит следующим образом (действителен при помещении в валидатор JSON):

{
    "contentItem": [
            {
            "contentID" : "1", 
            "contentVideo" : "file.mov",
            "contentThumbnail" : "url.jpg",
            "contentRating" : "5",
            "contentTitle" : "Guitar Lessons",
            "username" : "Username", 
            "realname" : "Real name",
            "contentTags" : [
                { "tag" : "Guitar"},
                { "tag" : "Intermediate"},
                { "tag" : "Chords"}
            ],      
            "contentAbout" : "Learn how to play guitar!",
            "contentTime" : [
                { "" : "", "" : "", "" : "", "" : ""},
                { "" : "", "" : "", "" : "", "" : ""}
            ],          
            "series" :[
                { "seriesVideo" : "file.mov", "seriesThumbnail" : "url.jpg", "seriesTime" : "time", "seriesNumber" : "1", "seriesTitle" : "How to Play Guitar" },
                { "videoFile" : "file.mov", "seriesThumbnail" : "url.jpg", "seriesTime" : "time", "seriesNumber" : "2", "seriesTitle" : "How to Play Guitar" }
            ]
        },{
            "contentID" : "2", 
            "contentVideo" : "file.mov",
            "contentThumbnail" : "url.jpg",
            "contentRating" : "5",
            "contentTitle" : "Guitar Lessons",
            "username" : "Username", 
            "realname" : "Real name",
            "contentTags" : [
                { "tag" : "Guitar"},
                { "tag" : "Intermediate"},
                { "tag" : "Chords"}
            ],      
            "contentAbout" : "Learn how to play guitar!",
            "contentTime" : [
                { "" : "", "" : "", "" : "", "" : ""},
                { "" : "", "" : "", "" : "", "" : ""}
            ],          
            "series" :[
                { "seriesVideo" : "file.mov", "seriesThumbnail" : "url.jpg", "seriesTime" : "time", "seriesNumber" : "1", "seriesTitle" : "How to Play Guitar" },
                { "videoFile" : "file.mov", "seriesThumbnail" : "url.jpg", "seriesTime" : "time", "seriesNumber" : "2", "seriesTitle" : "How to Play Guitar" }
            ]
        }
    ]
}

Я получил свой контроллер, фабрику и html, когда JSON был жестко закодирован внутри фабрики. Однако теперь, когда я заменил JSON на код $ http.get, он не работает. Я видел так много разных примеров как $ http, так и $ resource, но не знаю, куда идти. Ищу самое простое решение. Я просто пытаюсь получить данные для ng-repeat и подобных директив.

Завод:

theApp.factory('mainInfoFactory', function($http) { 
    var mainInfo = $http.get('content.json').success(function(response) {
        return response.data;
    });
    var factory = {}; // define factory object
    factory.getMainInfo = function() { // define method on factory object
        return mainInfo; // returning data that was pulled in $http call
    };
    return factory; // returning factory to make it ready to be pulled by the controller
});

Любая помощь приветствуется. Благодаря!

jstacks
источник
1
Не работает? Что оно делает? Выдает ошибку? Есть ли какой-нибудь вывод в консоли JavaScript?
Джош Ли
Консоль просто сообщает «Не удалось загрузить ресурс», а затем указывает путь к файлу console.json. Так что почему-то не загружает. Моя фабрика и JSON точно такие же, как вы видите выше. Когда я жестко кодирую JSON на заводе, он работает.
jstacks 05
1
Что вы используете в качестве серверной части? NodeJs или простой сервер на Python или что-то еще?
callmekatootie 05
Я просто пытаюсь разработать без бэкэнда (Rails). Таким образом, JSON - это просто файл .json с жестко закодированными данными. Предположительно похоже на то, что будет отображать серверная часть.
jstacks 05
Возможно, вам не понадобится ".data" в ответе .. измените его на - "return response;", если только ваш возвращенный JSON не заключен в объект 'data'.
Бхаскара Кемпайя

Ответы:

218

Хорошо, вот список вещей, на которые стоит обратить внимание:

1) Если вы не используете какой-либо веб-сервер и просто тестируете его с помощью file: //index.html, то вы, вероятно, столкнетесь с проблемами политики одного и того же происхождения. Видеть:

https://code.google.com/archive/p/browsersec/wikis/Part2.wiki#Same-origin_policy

Многие браузеры не разрешают локально размещенным файлам доступ к другим локально размещенным файлам. Firefox допускает это, но только в том случае, если загружаемый файл находится в той же папке, что и файл html (или подпапка).

2) Функция успеха, возвращаемая из $ http.get (), уже разделяет за вас объект результата:

$http({method: 'GET', url: '/someUrl'}).success(function(data, status, headers, config) {

Поэтому излишне вызывать успех с помощью функции (ответа) и возвращать response.data.

3) Функция успеха не возвращает результат переданной функции, поэтому она не делает того, что вы думаете:

var mainInfo = $http.get('content.json').success(function(response) {
        return response.data;
    });

Это ближе к тому, что вы планировали:

var mainInfo = null;
$http.get('content.json').success(function(data) {
    mainInfo = data;
});

4) Но что вы действительно хотите сделать, так это вернуть ссылку на объект со свойством, которое будет заполнено при загрузке данных, поэтому что-то вроде этого:

theApp.factory('mainInfo', function($http) { 

    var obj = {content:null};

    $http.get('content.json').success(function(data) {
        // you can do some processing here
        obj.content = data;
    });    

    return obj;    
});

mainInfo.content будет начинаться с нуля, и при загрузке данных он будет указывать на него.

В качестве альтернативы вы можете вернуть фактическое обещание, которое возвращает $ http.get, и использовать его:

theApp.factory('mainInfo', function($http) { 
    return $http.get('content.json');
});

А затем вы можете асинхронно использовать значение в вычислениях в контроллере:

$scope.foo = "Hello World";
mainInfo.success(function(data) { 
    $scope.foo = "Hello "+data.contentItem[0].username;
});
Карен Зиллес
источник
27
Эй, это ответ И угловой курс $ http по той же цене - Хороший ответ!
Мат
4
В вашем объяснении в разделе 4) не будет ли вызвана функция return obj до разрешения $ http.get ()? Просто спрашиваю, потому что я думаю, что это то, что со мной происходит.
Pathsofdesign
3
Да, это будет. Но закрытие, вызываемое при разрешении $ http.get (), сохраняет ссылку на obj. Он заполнит свойство содержимого, которое вы затем сможете использовать.
Карен Зиллес
В чем проблема использования второй формы №3 перед использованием №4?
Спенсер
1
Связанный обратный вызов .success () устарел. Вместо этого используйте .then (успех, ошибка).
Тимоти Перес,
21

Хочу отметить, что четвертая часть принятого ответа неверна .

theApp.factory('mainInfo', function($http) { 

var obj = {content:null};

$http.get('content.json').success(function(data) {
    // you can do some processing here
    obj.content = data;
});    

return obj;    
});

Приведенный выше код, как написал @Karl Zilles, завершится ошибкой, потому что objон всегда будет возвращаться до того, как получит данные (таким образом, значение всегда будет null), и это потому, что мы выполняем асинхронный вызов.

Подробности подобных вопросов обсуждаются в этом посте.


В Angular используйте $promiseдля обработки полученных данных, когда вы хотите выполнить асинхронный вызов.

Самый простой вариант -

theApp.factory('mainInfo', function($http) { 
    return {
        get:  function(){
            $http.get('content.json'); // this will return a promise to controller
        }
});


// and in controller

mainInfo.get().then(function(response) { 
    $scope.foo = response.data.contentItem;
});

Причина, по которой я не использую, successи errorя только что узнал из документа , эти два метода устарели.

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

Цян
источник
2
Используйте return $http.get('content.json');на заводе, иначе возврат будет нулевым.
Франческо,
2
Эй, просто предупреждаю. Причина, по которой он работает (вопреки вашему ответу здесь), заключается в том, что вы возвращаете ссылку на объект. Функция успеха также имеет ссылку на тот же объект. Когда функция ajax в конечном итоге возвращает, она обновляет свойство «content» в исходном возвращенном объекте. Попытайся. :-)
Карен Зиллес
1
Ps .successтеперь устарела. .thenВместо этого используйте . docs.angularjs.org/api/ng/service/$http
redfox05
4

этот ответ мне очень помог и указал мне в правильном направлении, но то, что сработало для меня и, надеюсь, других, так это:

menuApp.controller("dynamicMenuController", function($scope, $http) {
$scope.appetizers= [];
$http.get('config/menu.json').success(function(data) { 
    console.log("success!");
    $scope.appetizers = data.appetizers;
        console.log(data.appetizers);
    });    
});
jp093121
источник
6
разве вы не должны делать что-то подобное внутри службы?
Katana24
Никогда не делайте этого в контроллере! Плохо! Вы должны написать это как услугу. Хотя то, как вы назвали значение json, не является неправильным, у вас должна быть служба, возвращающая обещание, не выполняющая этого в контроллере. С точки зрения возможности повторного использования это тоже ужасно. Например, вы выполняете и $ http.get () каждый раз, когда загружаете контроллер, а не имеете кешированную версию вызова в службе.
Downpour046
1

У меня примерно эти проблемы. Мне нужно отладить приложение AngularJs из Visual Studio 2013.

По умолчанию IIS Express ограничивает доступ к локальным файлам (например, json).

Но сначала: JSON имеет синтаксис JavaScript.

Второе: файлы javascript разрешены.

Так:

  1. переименуйте JSON в JS ( data.json->data.js).

  2. правильная команда загрузки ($http.get('App/data.js').success(function (data) {...

  3. загрузить скрипт data.js в page ( <script src="App/data.js"></script>)

Затем используйте загруженные данные обычным образом. Конечно, это просто обходной путь.

Алекс Сэм
источник
1

++ Это сработало для меня. Это vanilla javascirptи хорошо для таких случаев, как устранение загромождения при тестировании с ngMocksбиблиотекой:

<!-- specRunner.html - keep this at the top of your <script> asset loading so that it is available readily -->
<!--  Frienly tip - have all JSON files in a json-data folder for keeping things organized-->
<script src="json-data/findByIdResults.js" charset="utf-8"></script>
<script src="json-data/movieResults.js" charset="utf-8"></script>

Это ваш javascriptфайл, содержащий JSONданные

// json-data/JSONFindByIdResults.js
var JSONFindByIdResults = {
     "Title": "Star Wars",
     "Year": "1983",
     "Rated": "N/A",
     "Released": "01 May 1983",
     "Runtime": "N/A",
     "Genre": "Action, Adventure, Sci-Fi",
     "Director": "N/A",
     "Writer": "N/A",
     "Actors": "Harrison Ford, Alec Guinness, Mark Hamill, James Earl Jones",
     "Plot": "N/A",
     "Language": "English",
     "Country": "USA",
     "Awards": "N/A",
     "Poster": "N/A",
     "Metascore": "N/A",
     "imdbRating": "7.9",
     "imdbVotes": "342",
     "imdbID": "tt0251413",
     "Type": "game",
     "Response": "True"
};

Наконец, работайте с данными JSON в любом месте вашего кода.

// working with JSON data in code
var findByIdResults = window.JSONFindByIdResults;

Примечание: - Это отлично подходит для тестирования и даже karma.conf.jsпринимает эти файлы для запуска тестов, как показано ниже. Кроме того, я рекомендую это только для устранения загромождения данных и testing/developmentсреды.

// extract from karma.conf.js
files: [
     'json-data/JSONSearchResultHardcodedData.js',
     'json-data/JSONFindByIdResults.js'
     ...
]

Надеюсь это поможет.

++ На основе этого ответа https://stackoverflow.com/a/24378510/4742733

ОБНОВИТЬ

Более простой способ, который сработал для меня, - просто включить в конец functionкода что-то, что возвращает JSON.

// within test code
let movies = getMovieSearchJSON();
.....
...
...
....
// way down below in the code
function getMovieSearchJSON() {
      return {
         "Title": "Bri Squared",
         "Year": "2011",
         "Rated": "N/A",
         "Released": "N/A",
         "Runtime": "N/A",
         "Genre": "Comedy",
         "Director": "Joy Gohring",
         "Writer": "Briana Lane",
         "Actors": "Brianne Davis, Briana Lane, Jorge Garcia, Gabriel Tigerman",
         "Plot": "N/A",
         "Language": "English",
         "Country": "USA",
         "Awards": "N/A",
         "Poster": "http://ia.media-imdb.com/images/M/MV5BMjEzNDUxMDI4OV5BMl5BanBnXkFtZTcwMjE2MzczNQ@@._V1_SX300.jpg",
         "Metascore": "N/A",
         "imdbRating": "8.2",
         "imdbVotes": "5",
         "imdbID": "tt1937109",
         "Type": "movie",
         "Response": "True"
   }
}
Аакаш
источник