AngularJS: file JSON $ http.get di fabbrica


84

Sto cercando di sviluppare localmente con solo un file JSON hardcoded. Il mio file JSON è il seguente (valido se inserito nel validatore 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" }
            ]
        }
    ]
}

Ho fatto funzionare il controller, la fabbrica e l'html quando il JSON era codificato all'interno della fabbrica. Tuttavia, ora che ho sostituito il JSON con il codice $ http.get, non funziona. Ho visto così tanti esempi diversi di $ http e $ resource ma non so dove andare. Sto cercando la soluzione più semplice. Sto solo cercando di estrarre dati per ng-repeat e direttive simili.

Fabbrica:

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

Qualsiasi aiuto è apprezzato. Grazie!


1
Non funziona? Che cosa fa? Genera un errore? C'è qualche output nella console JavaScript?
Josh Lee,

La console dice semplicemente "Impossibile caricare la risorsa" e quindi ha il percorso del file console.json. Quindi non lo sta caricando per qualche motivo. La mia fabbrica e JSON sono esattamente come vedi sopra. Quando inserisco il codice JSON in fabbrica, funziona.
jstacks

1
Cosa stai usando come backend? NodeJs o un semplice server basato su Python o qualcos'altro?
callmekatootie

Sto solo cercando di sviluppare escludendo il backend (Rails). Quindi il JSON è solo un file .json con i dati sopra codificati. Presumibilmente simile a quello che renderebbe il backend.
jstacks

Potrebbe non essere necessario ".data" sulla risposta .. passare a - "return response;", a meno che il JSON restituito non sia raggruppato in un oggetto "data".
Bhaskara Kempaiah

Risposte:


218

Ok, ecco un elenco di cose da esaminare:

1) Se non stai eseguendo un server web di alcun tipo e stai solo testando con file: //index.html, probabilmente stai riscontrando problemi con i criteri della stessa origine. Vedere:

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

Molti browser non consentono ai file ospitati localmente di accedere ad altri file ospitati localmente. Firefox lo consente, ma solo se il file che stai caricando è contenuto nella stessa cartella del file html (o una sottocartella).

2) La funzione di successo restituita da $ http.get () divide già l'oggetto risultato per te:

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

Quindi è ridondante chiamare il successo con funzione (risposta) e restituire response.data.

3) La funzione success non restituisce il risultato della funzione passata, quindi questo non fa quello che pensi che faccia:

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

Questo è più vicino a ciò che intendevi:

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

4) Ma quello che vuoi veramente fare è restituire un riferimento a un oggetto con una proprietà che verrà popolata quando i dati vengono caricati, quindi qualcosa del genere:

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 inizierà da null e quando i dati verranno caricati, punterà su di esso.

In alternativa puoi restituire la promessa effettiva restituita da $ http.get e utilizzarla:

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

E poi puoi usare il valore in modo asincrono nei calcoli in un controller:

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

27
Ehi, questa è una risposta E un corso angolare $ http allo stesso prezzo - Bella risposta!
Mat

4
Nella tua spiegazione al punto 4), "return obj" non verrà chiamato prima che $ http.get () sia stato risolto? Chiedo solo perché penso che sia quello che mi sta succedendo.
Pathsofdesign

3
Si lo farà. Ma la chiusura chiamata quando $ http.get () viene risolta mantiene un riferimento a 'obj'. Riempirà la proprietà del contenuto che puoi quindi utilizzare.
Karen Zilles

Qual è il problema con l'utilizzo della seconda forma di # 3 rispetto all'uso di # 4?
Spencer

1
Il callback concatenato .success () è stato deprecato. Usa .then (successo, errore) invece.
Timothy Perez

21

Volevo sottolineare che la quarta parte della risposta accettata è sbagliata .

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

Il codice sopra come ha scritto @Karl Zilles fallirà perché objverrà sempre restituito prima di ricevere i dati (quindi il valore sarà sempre null) e questo perché stiamo effettuando una chiamata asincrona.

I dettagli di domande simili sono discussi in questo post


In Angular, usa $promise per gestire i dati recuperati quando si desidera effettuare una chiamata asincrona.

La versione più semplice è

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

Il motivo per cui non lo uso successed errorè che l'ho appena scoperto dal documento , questi due metodi sono deprecati.

Il $httpsuccesso e l'errore dei metodi di promessa precedenti sono stati deprecati. Usa theninvece il metodo standard .


2
Utilizzare return $http.get('content.json');in fabbrica, altrimenti il ​​reso è nullo.
Francesco

2
Ehi, solo un avvertimento. Il motivo per cui funziona (contrariamente alla tua risposta qui) è che stai restituendo un riferimento a un oggetto. La funzione di successo ha anche un riferimento a quello stesso oggetto. Quando la funzione ajax alla fine restituisce, aggiorna la proprietà "content" nell'oggetto originale che è stato restituito. Provalo. :-)
Karen Zilles

1
Ps .successè ora deprecato. Usa .theninvece. docs.angularjs.org/api/ng/service/$http
redfox05

4

questa risposta mi ha aiutato molto e mi ha indirizzato nella giusta direzione, ma ciò che ha funzionato per me, e si spera per altri, è:

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
non dovresti fare qualcosa di simile all'interno di un servizio?
Katana24

Non farlo mai in un controller! cattivo! Dovresti averlo scritto come servizio. Sebbene il modo in cui hai chiamato il valore json non sia sbagliato, dovresti avere un servizio che restituisce la promessa di non farlo nel controller. Anche dal punto di vista della riutilizzabilità questo è orribile. Ad esempio, stai eseguendo e $ http.get () ogni singola volta che carichi il controller rispetto a una versione memorizzata nella cache della chiamata in un servizio.
Downpour046

1

Ho approssimativamente questi problemi. Ho bisogno di eseguire il debug dell'applicazione AngularJs da Visual Studio 2013.

Per impostazione predefinita, IIS Express ha limitato l'accesso ai file locali (come json).

Ma prima: JSON ha la sintassi JavaScript.

Secondo: i file javascript sono consentiti.

Così:

  1. rinomina JSON in JS ( data.json->data.js).

  2. comando di caricamento corretto ($http.get('App/data.js').success(function (data) {...

  3. carica lo script data.js in page ( <script src="App/data.js"></script>)

Quindi utilizzare i dati caricati come al solito. Ovviamente è solo una soluzione alternativa.


1

++ Questo ha funzionato per me. È vanilla javascirptutile per casi d'uso come il disordine durante i test con la ngMockslibreria:

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

Questo è il tuo javascriptfile che contiene i JSONdati

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

Infine, lavora con i dati JSON ovunque nel tuo codice

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

Nota: - Questo è ottimo per i test e karma.conf.jsaccetta anche questi file per eseguire i test come mostrato di seguito. Inoltre, lo consiglio solo per liberare i dati e l' testing/developmentambiente.

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

Spero che sia di aiuto.

++ Basato su questa risposta https://stackoverflow.com/a/24378510/4742733

AGGIORNARE

Un modo più semplice che ha funzionato per me è semplicemente includere un functionin fondo al codice che restituisce qualunque cosa 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"
   }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.