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, так і $ ресурсу, але не знаю, куди йти. Шукаю найпростішого рішення. Я просто намагаюся отримати дані для 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
});

Будь-яка допомога цінується. Дякую!


1
Це не працює? Що це робить? Чи виникає помилка? Чи є вихід у консолі JavaScript?
Джош Лі

Консоль просто говорить "Не вдалося завантажити ресурс", а потім має шлях до файлу console.json. Отже, це не завантажується з якихось причин. Моя фабрика та JSON точно такі, як ви бачите вище. Коли я жорстко кодую JSON на завод, це працює.
jstacks

1
Що ви використовуєте як свій сервер? NodeJs чи простий сервер на основі python чи щось інше?
callmekatootie

Я просто намагаюся розробити, виключаючи бекенд (Rails). Отже, JSON - це просто файл .json із наведеними вище твердокодованими даними. Імовірно, схоже на те, що робить бэкенд.
jstacks

Можливо, вам не знадобляться ".data" у відповіді .. змініть на - "return response;", якщо тільки ваш повернутий JSON не входить до об'єкта 'data'.
Bhaskara Kempaiah

Відповіді:


218

Гаразд, ось список речей, на які слід звернути увагу:

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;
});

27
Гей, це відповідь І кутовий курс $ http за ту ж ціну - Приємна відповідь!
мат

4
У вашому поясненні під 4), чи не буде викликано 'return obj' до того, як буде вирішено $ http.get ()? Просто запитую, бо я думаю, що це те, що відбувається зі мною.
Pathsofdesign

3
Так це буде. Але закриття, викликане при вирішенні $ http.get (), зберігає посилання на 'obj'. Він заповнить властивість вмісту, яку ви потім зможете використовувати.
Karen Zilles

Що проблематично при використанні другої форми №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
.successНаразі PS застарілий. Використовуйте .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);
    });    
});

6
чи не слід робити щось подібне всередині служби?
Katana24

Ніколи не робіть цього в контролері! погано! Ви повинні написати це як послугу. Хоча те, як ви викликали значення json, не є помилковим, у вас повинна бути служба, яка повертає обіцянку, не роблячи цього в контролері. І з точки зору багаторазового використання це жахливо. Наприклад, ви виконуєте та $ http.get () кожного разу, коли завантажуєте контролер проти того, щоб мати кешовану версію виклику в службі.
Злива046,

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 на сторінку ( <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

ОНОВЛЕННЯ

Більш простий спосіб, який працював для мене, це просто включити a 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"
   }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.