84 votes

AngularJS : factory $http.get JSON file

Je cherche à développer localement avec un simple fichier JSON codé en dur. Mon fichier JSON est le suivant (valide lorsqu'il est placé dans le validateur 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" }
            ]
        }
    ]
}

J'ai réussi à faire fonctionner mon contrôleur, ma fabrique et le html alors que le JSON était codé en dur dans la fabrique. Cependant, maintenant que j'ai remplacé le JSON par le code $http.get, ça ne fonctionne pas. J'ai vu tellement d'exemples différents de $http et $resource, mais je ne sais pas où aller. Je cherche la solution la plus simple. J'essaie simplement d'extraire des données pour ng-repeat et des directives similaires.

Usine :

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

Toute aide est appréciée. Merci.

1 votes

Ça ne marche pas ? Qu'est-ce qu'il fait ? Lance-t-il une erreur ? Y a-t-il une sortie dans la console JavaScript ?

0 votes

La console indique simplement "Failed to load resource" (échec du chargement de la ressource), puis le chemin du fichier console.json. Donc, il ne le charge pas pour une raison quelconque. Mon factory et mon JSON sont exactement comme vous le voyez ci-dessus. Lorsque je code en dur le JSON dans la fabrique, cela fonctionne.

1 votes

Qu'utilisez-vous comme backend ? NodeJs ou un simple serveur basé sur python ou autre chose ?

218voto

Karl Zilles Points 3549

Ok, voici une liste de choses à vérifier :

1) Si vous n'utilisez pas de serveur Web et que vous testez simplement file://index.html, vous êtes probablement confronté à des problèmes de politique d'origine identique. Voir :

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

De nombreux navigateurs ne permettent pas aux fichiers hébergés localement d'accéder à d'autres fichiers hébergés localement. Firefox le permet, mais seulement si le fichier que vous chargez est contenu dans le même dossier que le fichier html (ou un sous-dossier).

2) La fonction de succès renvoyée par $http.get() divise déjà l'objet de résultat pour vous :

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

Il est donc redondant d'appeler le succès avec function(response) et de retourner response.data.

3) La fonction de succès ne renvoie pas le résultat de la fonction que vous lui passez, donc cela ne fait pas ce que vous pensez qu'il fait :

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

C'est plus proche de ce que vous vouliez :

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

4) Mais ce que vous voulez vraiment faire, c'est retourner une référence à un objet avec une propriété qui sera remplie lorsque les données seront chargées, donc quelque chose comme ceci :

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 sera nul au départ, et lorsque les données seront chargées, il pointera vers lui.

Vous pouvez également renvoyer la promesse réelle que $http.get renvoie et l'utiliser :

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

Vous pouvez ensuite utiliser cette valeur de manière asynchrone dans les calculs d'un contrôleur :

$scope.foo = "Hello World";
mainInfo.success(function(data) { 
    $scope.foo = "Hello "+data.contentItem[0].username;
});

27 votes

Hey c'est une réponse ET un cours angular $http pour le même prix - Belle réponse !

4 votes

Dans votre explication sous 4), le "return obj" ne sera-t-il pas appelé avant que $http.get() ne soit résolu ? Je demande simplement parce que je pense que c'est ce qui m'arrive.

3 votes

Oui, il le fera. Mais la fermeture appelée lorsque $http.get() est résolu conserve une référence à 'obj'. Elle remplira la propriété content que vous pourrez ensuite utiliser.

21voto

Qiang Points 3

Je voulais noter que le la quatrième partie de la réponse acceptée est fausse .

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

Le code ci-dessus, comme l'a écrit @Karl Zilles, échouera parce que obj sera toujours retourné avant qu'il ne reçoive des données (ainsi la valeur sera toujours null ) et c'est parce que nous faisons un Appel asynchrone.

Les détails de questions similaires sont discutés dans ce poste


En Angular, utilisez $promise pour traiter les données récupérées lorsque vous voulez faire un appel asynchrone.

La version la plus simple est

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 raison pour laquelle je n'utilise pas success y error est que je viens d'apprendre par le doc ces deux méthodes sont obsolètes.

El $http Les anciennes méthodes de promesse success et error ont été dépréciées. Utilisez la méthode standard then à la place.

2 votes

Utilisez return $http.get('content.json'); dans l'usine, sinon le retour est nul.

2 votes

Hey, juste une info. La raison pour laquelle cela fonctionne (contrairement à votre réponse ici) est que vous renvoyez une référence à un objet. La fonction de succès a également une référence à ce même objet. Quand la fonction ajax revient finalement, elle met à jour la propriété "content" dans l'objet original qui a été retourné. Essayez-le. :-)

1 votes

P.s. .success est maintenant déprécié. Utilisez .then à la place. docs.angularjs.org/api/ng/service/$http

4voto

jp093121 Points 492

Cette réponse m'a beaucoup aidée et m'a orientée dans la bonne direction, mais ce qui a fonctionné pour moi, et j'espère pour d'autres, est le suivant :

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 votes

Ne devriez-vous pas faire quelque chose comme ça à l'intérieur d'un service ?

0 votes

Ne jamais faire cela dans un contrôleur ! mauvais ! Vous devriez écrire cela comme un service. Même si la façon dont vous avez appelé la valeur json n'est pas mauvaise, vous devriez avoir un service qui renvoie la promesse et ne pas le faire dans le contrôleur. Du point de vue de la réutilisation, c'est également horrible. Par exemple, vous exécutez $http.get() à chaque fois que vous chargez le contrôleur au lieu d'avoir une version en cache de l'appel dans un service.

1voto

Alex Sam Points 9

J'ai à peu près le même problème. Je dois déboguer une application AngularJs à partir de Visual Studio 2013.

Par défaut, IIS Express restreint l'accès aux fichiers locaux (comme json).

Mais, d'abord : Les JSON ont une syntaxe JavaScript.

Deuxièmement : les fichiers javascript sont autorisés.

Donc :

  1. renommer JSON en JS ( data.json->data.js ).

  2. commande de chargement correcte ( $http.get('App/data.js').success(function (data) {...

  3. charger script data.js à la page ( <script src="App/data.js"></script> )

Ensuite, utilisez les données chargées de manière habituelle. Il ne s'agit que d'une solution de rechange, bien sûr.

1voto

Akash Points 5697

++ Ça a marché pour moi. C'est vanilla javascirpt et bon pour des cas d'utilisation tels que le désencombrement lors de tests avec des ngMocks bibliothèque :

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

C'est votre javascript qui contient le JSON données

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

Enfin, vous pouvez utiliser les données JSON n'importe où dans votre code.

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

Note : - C'est idéal pour les tests et même karma.conf.js accepte ces fichiers pour exécuter des tests comme indiqué ci-dessous. Aussi, je recommande ceci uniquement pour désencombrer les données et testing/development l'environnement.

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

J'espère que cela vous aidera.

++ Construit sur la base de cette réponse https://stackoverflow.com/a/24378510/4742733

UPDATE

Une méthode plus simple qui a fonctionné pour moi est d'inclure un fichier function en bas du code retournant ce qui est 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"
   }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X