AngularJS: Factory $ http.get JSON-Datei

84

Ich möchte lokal mit nur einer fest codierten JSON-Datei entwickeln. Meine JSON-Datei lautet wie folgt (gültig, wenn sie in den JSON-Validator gestellt wird):

{
    "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" }
            ]
        }
    ]
}

Ich habe meinen Controller, meine Factory und mein HTML zum Laufen gebracht, als der JSON in der Factory fest codiert wurde. Jetzt, da ich den JSON durch den Code $ http.get ersetzt habe, funktioniert er jedoch nicht mehr. Ich habe so viele verschiedene Beispiele für $ http und $ resource gesehen, bin mir aber nicht sicher, wohin ich gehen soll. Ich suche die einfachste Lösung. Ich versuche nur, Daten für ng-repeat und ähnliche Anweisungen abzurufen.

Fabrik:

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

Jede Hilfe wird geschätzt. Vielen Dank!

jstacks
quelle
1
Es funktioniert nicht? Was tut es? Wirft es einen Fehler? Gibt es eine Ausgabe in der JavaScript-Konsole?
Josh Lee
Die Konsole sagt nur "Ressource konnte nicht geladen werden" und hat dann den Dateipfad console.json. Es wird also aus irgendeinem Grund nicht geladen. Meine Fabrik und JSON sind genau so, wie Sie oben sehen. Wenn ich den JSON in der Fabrik fest codiere, funktioniert er.
Jstacks
1
Was verwenden Sie als Backend? NodeJs oder ein einfacher Python-basierter Server oder etwas anderes?
Callmekatootie
Ich versuche nur, ohne das Backend (Rails) zu entwickeln. Der JSON ist also nur eine .json-Datei mit den oben fest codierten Daten. Vermutlich ähnlich wie das Backend.
Jstacks
Möglicherweise benötigen Sie nicht ".data" für die Antwort. Wechseln Sie zu - "return response;", es sei denn, Ihr zurückgegebener JSON ist in einem 'data'-Objekt gebündelt.
Bhaskara Kempaiah

Antworten:

218

Okay, hier ist eine Liste von Dingen, die Sie untersuchen sollten:

1) Wenn Sie keinen Webserver ausführen und nur mit der Datei //index.html testen, treten wahrscheinlich Probleme mit Richtlinien gleichen Ursprungs auf. Sehen:

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

In vielen Browsern können lokal gehostete Dateien nicht auf andere lokal gehostete Dateien zugreifen. Firefox erlaubt dies jedoch nur, wenn sich die geladene Datei im selben Ordner befindet wie die HTML-Datei (oder ein Unterordner).

2) Die von $ http.get () zurückgegebene Erfolgsfunktion teilt das Ergebnisobjekt bereits für Sie auf:

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

Es ist also überflüssig, Erfolg mit Funktion (Antwort) aufzurufen und response.data zurückzugeben.

3) Die Erfolgsfunktion gibt nicht das Ergebnis der Funktion zurück, die Sie übergeben haben. Dies tut also nicht das, was Sie denken:

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

Dies ist näher an dem, was Sie beabsichtigt haben:

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

4) Was Sie aber wirklich tun möchten, ist, einen Verweis auf ein Objekt mit einer Eigenschaft zurückzugeben, die beim Laden der Daten ausgefüllt wird.

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 startet mit null und zeigt beim Laden der Daten darauf.

Alternativ können Sie das tatsächliche Versprechen, das $ http.get zurückgibt, zurückgeben und Folgendes verwenden:

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

Und dann können Sie den Wert asynchron in Berechnungen in einer Steuerung verwenden:

$scope.foo = "Hello World";
mainInfo.success(function(data) { 
    $scope.foo = "Hello "+data.contentItem[0].username;
});
Karen Zilles
quelle
27
Hey, das ist eine Antwort UND ein eckiger $ http-Kurs zum gleichen Preis - Schöne Antwort!
Mat
4
Wird in Ihrer Erklärung unter 4) das 'return obj' nicht aufgerufen, bevor $ http.get () aufgelöst wird? Ich frage nur, weil ich denke, dass mir das passiert.
Pathsofdesign
3
Ja, es wird. Der Abschluss, der aufgerufen wird, wenn $ http.get () aufgelöst wird, enthält jedoch einen Verweis auf 'obj'. Es füllt die Inhaltseigenschaft aus, die Sie dann verwenden können.
Karen Zilles
Was ist problematisch bei der Verwendung der zweiten Form von # 3 gegenüber der Verwendung von # 4?
Spencer
1
Der verkettete Rückruf .success () ist veraltet. Verwenden Sie stattdessen .then (Erfolg, Fehler).
Timothy Perez
21

Ich wollte darauf hinweisen, dass der vierte Teil von Accepted Answer falsch ist .

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

Der obige Code, wie er von @Karl Zilles geschrieben wurde, schlägt fehl, da er objimmer zurückgegeben wird, bevor er Daten empfängt (daher ist der Wert immer null), und weil wir einen asynchronen Aufruf tätigen.

Die Details ähnlicher Fragen werden in diesem Beitrag behandelt


Verwenden Sie $promisein Angular, um mit den abgerufenen Daten umzugehen, wenn Sie einen asynchronen Aufruf tätigen möchten.

Die einfachste Version ist

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

Der Grund, den ich nicht benutze successund den errorich gerade aus dem Dokument herausgefunden habe , ist, dass diese beiden Methoden veraltet sind.

Der $httpErfolg und Fehler der alten Versprechensmethoden wurde verworfen. Verwenden Sie thenstattdessen die Standardmethode .

Qiang
quelle
2
Verwendung return $http.get('content.json');im Werk, andernfalls ist return null.
Francesco
2
Hey, nur ein Kopf hoch. Der Grund, warum es funktioniert (entgegen Ihrer Antwort hier), ist, dass Sie einen Verweis auf ein Objekt zurückgeben. Die Erfolgsfunktion verweist auch auf dasselbe Objekt. Wenn die Ajax-Funktion schließlich zurückgibt, aktualisiert sie die Eigenschaft "content" im ursprünglichen Objekt, das zurückgegeben wurde. Versuch es. :-)
Karen Zilles
1
Ps .successist jetzt veraltet. Verwenden Sie .thenstattdessen. docs.angularjs.org/api/ng/service/$http
redfox05
4

Diese Antwort hat mir sehr geholfen und mich in die richtige Richtung gelenkt, aber was für mich und hoffentlich für andere funktioniert hat, ist:

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
quelle
6
sollten Sie so etwas nicht in einem Dienst tun?
Katana24
Mach das niemals in einem Controller! Schlecht! Sie sollten dies als Service schreiben lassen. Obwohl die Art und Weise, wie Sie den json-Wert aufgerufen haben, nicht falsch ist, sollte ein Dienst das Versprechen zurückgeben, dies nicht im Controller zu tun. Auch unter dem Gesichtspunkt der Wiederverwendbarkeit ist dies schrecklich. Beispielsweise führen Sie jedes Mal, wenn Sie den Controller laden, und $ http.get () aus, anstatt eine zwischengespeicherte Version des Aufrufs in einem Dienst zu haben.
Downpour046
1

Ich habe ungefähr dieses Problem. Ich muss die AngularJs-Anwendung aus Visual Studio 2013 debuggen.

Standardmäßig beschränkt IIS Express den Zugriff auf lokale Dateien (wie z. B. json).

Aber zuerst: JSON hat JavaScript-Syntax.

Zweitens: Javascript-Dateien sind zulässig.

So:

  1. Benennen Sie JSON in JS ( data.json->data.js) um.

  2. korrekter Ladebefehl ($http.get('App/data.js').success(function (data) {...

  3. Laden Sie das Skript data.js auf page ( <script src="App/data.js"></script>)

Verwenden Sie als nächstes die geladenen Daten auf übliche Weise. Es ist natürlich nur eine Problemumgehung.

Alex Sam
quelle
1

++ Das hat bei mir funktioniert. Es ist vanilla javascirptund gut für Anwendungsfälle wie das Aufräumen beim Testen mit der ngMocksBibliothek:

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

Dies ist Ihre javascriptDatei, die die JSONDaten enthält

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

Schließlich arbeiten Sie mit den JSON-Daten an einer beliebigen Stelle in Ihrem Code

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

Hinweis: - Dies ist ideal zum Testen und karma.conf.jsakzeptiert diese Dateien sogar zum Ausführen von Tests (siehe unten). Außerdem empfehle ich dies nur, um Daten und testing/developmentUmgebung übersichtlicher zu gestalten .

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

Hoffe das hilft.

++ Aufbauend auf dieser Antwort https://stackoverflow.com/a/24378510/4742733

AKTUALISIEREN

Eine einfachere Möglichkeit, die für mich funktioniert hat, besteht darin, functionam Ende des Codes ein Zeichen einzufügen, das alles zurückgibt 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"
   }
}
Akash
quelle