AngularJS: factory $http.get JSON файл
Я ищу локальную разработку только с жестко закодированным файлом 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" }
]
}
]
}
Я получил свой контроллер, factory и html, работающий, когда JSON был жестко закодирован внутри factory. Однако теперь, когда я заменил JSON кодом $http.get, он не работает. Я видел так много разных примеров как $http, так и $resource, но не уверен, куда идти. Я ищу простейшее решение. Я просто пытаюсь извлечь данные для ng-repeat и аналогичных директив.
Factory:
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
});
Приветствуется всяческая помощь. Спасибо!
Ответы
Ответ 1
Хорошо, вот список вещей, на которые нужно смотреть:
1) Если вы не используете какой-либо веб-сервер и просто проверяете его с файлом://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) и return 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;
});
Ответ 2
Я хотел отметить, что четвертая часть принятого ответа неверна
.
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
, я только что узнал из doc, эти два методы устарели.
Успехи и ошибки в устаревших обещаниях $http
устарели. Вместо этого используйте стандартный метод then
.
Ответ 3
этот ответ очень помог мне и указал мне в правильном направлении, но то, что сработало для меня, и, надеюсь, другие:
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);
});
});
Ответ 4
У меня примерно такая проблема. Мне нужно отлаживать приложение AngularJs из Visual Studio 2013.
По умолчанию IIS Express ограничивает доступ к локальным файлам (например, json).
Но, во-первых: JSON имеет синтаксис JavaScript.
Во-вторых: разрешены файлы javascript.
Итак:
-
переименуйте JSON в JS (data.json->data.js
).
-
правильная команда загрузки ($http.get('App/data.js').success(function (data) {...
-
загрузить script data.js на страницу (<script src="App/data.js"></script>
)
Затем используйте загруженные данные обычным способом. Это, конечно, обходное решение.
Ответ 5
++ Это сработало для меня. Он 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'
...
]
Надеюсь, что это поможет.
++ Построенный поверх этого ответа fooobar.com/info/51675/...
UPDATE
Более простой способ, который работал у меня, это просто включить 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/[email protected]@._V1_SX300.jpg",
"Metascore": "N/A",
"imdbRating": "8.2",
"imdbVotes": "5",
"imdbID": "tt1937109",
"Type": "movie",
"Response": "True"
}
}