AngularJS: archivo JSON de fábrica $ http.get

84

Estoy buscando desarrollar localmente con solo un archivo JSON codificado. Mi archivo JSON es el siguiente (válido cuando se coloca en el validador 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" }
            ]
        }
    ]
}

He conseguido que mi controlador, fábrica y html funcionen cuando el JSON estaba codificado dentro de la fábrica. Sin embargo, ahora que reemplacé el JSON con el código $ http.get, no funciona. He visto tantos ejemplos diferentes de $ http y $ resource, pero no estoy seguro de a dónde ir. Busco la solución más sencilla. Solo estoy tratando de extraer datos para ng-repeat y directivas similares.

Fábrica:

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

Se agradece cualquier ayuda. ¡Gracias!

jstacks
fuente
1
¿No funciona? ¿Qué hace? ¿Lanza un error? ¿Hay alguna salida en la consola de JavaScript?
Josh Lee
La consola simplemente dice "No se pudo cargar el recurso" y luego tiene la ruta del archivo console.json. Entonces no lo está cargando por alguna razón. Mi fábrica y JSON son exactamente como ve arriba. Cuando codifico el JSON en la fábrica, funciona.
jstacks
1
¿Qué estás usando como tu backend? ¿NodeJs o un simple servidor basado en Python o algo más?
callmekatootie
Solo estoy tratando de desarrollar excluyendo el backend (Rails). Entonces, el JSON es solo un archivo .json con los datos anteriores codificados. Presumiblemente similar a lo que representaría el backend.
jstacks
Es posible que no necesite ".data" en la respuesta .. cambie a - "respuesta de retorno;", a menos que su JSON devuelto esté incluido dentro de un objeto de 'datos'.
Bhaskara Kempaiah

Respuestas:

218

De acuerdo, aquí hay una lista de cosas a considerar:

1) Si no está ejecutando un servidor web de ningún tipo y solo está probando con file: //index.html, es probable que tenga problemas con la política del mismo origen. Ver:

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

Muchos navegadores no permiten que los archivos alojados localmente accedan a otros archivos alojados localmente. Firefox lo permite, pero solo si el archivo que está cargando está contenido en la misma carpeta que el archivo html (o una subcarpeta).

2) La función de éxito devuelta por $ http.get () ya divide el objeto de resultado para usted:

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

Por lo tanto, es redundante llamar al éxito con la función (respuesta) y devolver response.data.

3) La función de éxito no devuelve el resultado de la función que le pasa, por lo que esto no hace lo que cree que hace:

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

Esto está más cerca de lo que pretendías:

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

4) Pero lo que realmente desea hacer es devolver una referencia a un objeto con una propiedad que se completará cuando se carguen los datos, así que algo como esto:

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 comenzará con un valor nulo y, cuando se carguen los datos, apuntará a él.

Alternativamente, puede devolver la promesa real que devuelve $ http.get y usarla:

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

Y luego puede usar el valor de forma asincrónica en cálculos en un controlador:

$scope.foo = "Hello World";
mainInfo.success(function(data) { 
    $scope.foo = "Hello "+data.contentItem[0].username;
});
Karen Zilles
fuente
27
Oye, esa es una respuesta Y un curso angular de $ http por el mismo precio: ¡Buena respuesta!
Mat
4
En su explicación en 4), ¿no se llamará al 'return obj' antes de que se resuelva $ http.get ()? Solo pregunto porque creo que eso es lo que me está pasando.
Pathsofdesign
3
Sí lo será. Pero el cierre llamado cuando se resuelve $ http.get () mantiene una referencia a 'obj'. Completará la propiedad de contenido que luego puede usar.
Karen Zilles
¿Cuál es el problema de usar la segunda forma del n. ° 3 en lugar del n. ° 4?
Spencer
1
La devolución de llamada encadenada .success () ha quedado obsoleta. Utilice .then (éxito, error) en su lugar.
Timothy Perez
21

Quería señalar que la cuarta parte de la respuesta aceptada es incorrecta .

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

El código anterior como escribió @Karl Zilles fallará porque objsiempre se devolverá antes de recibir datos (por lo tanto, el valor siempre será null) y esto se debe a que estamos haciendo una llamada asincrónica.

Los detalles de preguntas similares se discuten en esta publicación.


En Angular, utilícelo $promisepara tratar los datos obtenidos cuando desee realizar una llamada asincrónica.

La versión más simple es

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

La razón por la que no uso successy errores que me acabo de enterar por el documento , estos dos métodos están en desuso.

Los $httpmétodos de promesa heredados éxito y error han quedado obsoletos. En su lugar, utilice el thenmétodo estándar .

Qiang
fuente
2
Usar return $http.get('content.json');en fábrica, de lo contrario la devolución es nula.
Francesco
2
Oye, solo un aviso. La razón por la que funciona (al contrario de su respuesta aquí) es que está devolviendo una referencia a un objeto. La función de éxito también tiene una referencia a ese mismo objeto. Cuando la función ajax finalmente regresa, actualiza la propiedad "content" en el objeto original que se devolvió. Intentalo. :-)
Karen Zilles
1
Ps .successahora está en desuso. Úselo en su .thenlugar. docs.angularjs.org/api/ng/service/$http
redfox05
4

esta respuesta me ayudó mucho y me indicó la dirección correcta, pero lo que funcionó para mí, y con suerte para otros, es:

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
fuente
6
¿No deberías hacer algo como esto dentro de un servicio?
Katana24
¡Nunca hagas esto en un controlador! ¡malo! Debería tener esto escrito como un servicio. Aunque la forma en que llamó al valor json no es incorrecta, debe tener un Servicio que devuelva la promesa de no hacer esto en el controlador. Desde el punto de vista de la reutilización, esto también es horrible. Por ejemplo, está realizando y $ http.get () cada vez que carga el controlador frente a tener una versión en caché de la llamada en un servicio.
Downpour046
1

Tengo aproximadamente estos problemas. Necesito depurar la aplicación AngularJs de Visual Studio 2013.

De forma predeterminada, IIS Express restringe el acceso a archivos locales (como json).

Pero, primero: JSON tiene sintaxis JavaScript.

Segundo: se permiten archivos javascript.

Entonces:

  1. cambiar el nombre de JSON a JS ( data.json->data.js).

  2. comando de carga correcto ($http.get('App/data.js').success(function (data) {...

  3. cargar script data.js a la página ( <script src="App/data.js"></script>)

A continuación, utilice los datos cargados de la manera habitual. Es solo una solución, por supuesto.

Alex Sam
fuente
1

++ Esto funcionó para mí. Es vanilla javascirptbueno para casos de uso como el desorden cuando se prueba con la ngMocksbiblioteca:

<!-- 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>

Este es su javascriptarchivo que contiene los JSONdatos

// 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"
};

Finalmente, trabaje con los datos JSON en cualquier lugar de su código

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

Nota: - Esto es excelente para realizar pruebas e incluso karma.conf.jsacepta estos archivos para ejecutar pruebas como se muestra a continuación. Además, recomiendo esto solo para ordenar los datos y el testing/developmententorno.

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

Espero que esto ayude.

++ Construido sobre esta respuesta https://stackoverflow.com/a/24378510/4742733

ACTUALIZAR

Una forma más fácil que funcionó para mí es simplemente incluir un functionen la parte inferior del código que devuelve lo que sea 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"
   }
}
Aakash
fuente