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

84

Estou procurando desenvolver localmente com apenas um arquivo JSON codificado. Meu arquivo JSON é o seguinte (válido quando colocado no 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" }
            ]
        }
    ]
}

Coloquei meu controlador, fábrica e html funcionando quando o JSON foi codificado dentro da fábrica. No entanto, agora que substituí o JSON pelo código $ http.get, ele não funciona. Já vi tantos exemplos diferentes de $ http e $ resource, mas não tenho certeza para onde ir. Estou procurando a solução mais simples. Estou apenas tentando obter dados para diretivas ng-repeat e semelhantes.

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

Toda e qualquer ajuda é apreciada. Obrigado!

jstacks
fonte
1
Não funciona? O que isso faz? Isso gera um erro? Existe alguma saída no console JavaScript?
Josh Lee
O console apenas diz "Falha ao carregar o recurso" e tem o caminho do arquivo console.json. Portanto, não está carregando por algum motivo. Minha fábrica e JSON são exatamente como você viu acima. Quando codifico o JSON na fábrica, ele funciona.
jstacks de
1
O que você está usando como back-end? NodeJs ou um servidor baseado em python simples ou algo mais?
callmekatootie
Só estou tentando desenvolver excluindo o backend (Rails). Portanto, o JSON é apenas um arquivo .json com os dados acima codificados. Presumivelmente semelhante ao que o back-end renderizaria.
jstacks de
Talvez você não precise de ".data" na resposta .. mude para - "return response;", a menos que o JSON retornado esteja agrupado dentro de um objeto 'data'.
Bhaskara Kempaiah

Respostas:

218

Ok, aqui está uma lista de coisas a serem examinadas:

1) Se você não estiver executando um servidor da web de qualquer tipo e apenas testando com o arquivo: //index.html, provavelmente você está enfrentando problemas de política de mesma origem. Vejo:

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

Muitos navegadores não permitem que arquivos hospedados localmente acessem outros arquivos hospedados localmente. O Firefox permite, mas apenas se o arquivo que você está carregando estiver na mesma pasta do arquivo html (ou em uma subpasta).

2) A função de sucesso retornada de $ http.get () já divide o objeto de resultado para você:

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

Portanto, é redundante chamar o sucesso com função (resposta) e retornar response.data.

3) A função de sucesso não retorna o resultado da função que você passou, então ela não faz o que você pensa:

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

Isso está mais próximo do que você pretendia:

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

4) Mas o que você realmente deseja fazer é retornar uma referência a um objeto com uma propriedade que será preenchida quando os dados forem carregados, algo assim:

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 iniciará como nulo e, quando os dados forem carregados, ele apontará para eles.

Como alternativa, você pode retornar a promessa real que $ http.get retorna e usar:

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

E então você pode usar o valor de forma assíncrona em cálculos em um controlador:

$scope.foo = "Hello World";
mainInfo.success(function(data) { 
    $scope.foo = "Hello "+data.contentItem[0].username;
});
Karen Zilles
fonte
27
Ei, isso é uma resposta E um curso $ http angular pelo mesmo preço - Boa resposta!
Mat,
4
Em sua explicação em 4), o 'return obj' não será chamado antes de $ http.get () ser resolvido? Só perguntando porque acho que é isso que está acontecendo comigo.
Pathsofdesign
3
Sim vai. Mas o encerramento chamado quando $ http.get () é resolvido mantém uma referência a 'obj'. Ele preencherá a propriedade de conteúdo que você poderá usar.
Karen Zilles de
Qual é o problema de usar a segunda forma de # 3 em vez de # 4?
Spencer
1
O retorno de chamada encadeado .success () foi descontinuado. Use .then (sucesso, erro).
Timothy Perez,
21

Gostaria de observar que a quarta parte da Resposta Aceita está errada .

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

O código acima, como escreveu @Karl Zilles, falhará porque objsempre será retornado antes de receber os dados (portanto, o valor sempre será null) e isso ocorre porque estamos fazendo uma chamada assíncrona.

Os detalhes de questões semelhantes são discutidos nesta postagem


No Angular, use $promise para lidar com os dados buscados quando quiser fazer uma chamada assíncrona.

A versão mais simples é

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

Não uso successe erroracabei de descobrir no documento que esses dois métodos estão obsoletos.

Os $httpmétodos de promessa legados de sucesso e erro foram descontinuados. Use o thenmétodo padrão .

Qiang
fonte
2
Use return $http.get('content.json');na fábrica, caso contrário, o retorno é nulo.
Francesco
2
Ei, só um aviso. O motivo pelo qual funciona (ao contrário da sua resposta aqui) é que você está retornando uma referência a um objeto. A função de sucesso também tem uma referência a esse mesmo objeto. Quando a função ajax eventualmente retorna, ela atualiza a propriedade "content" no objeto original que foi retornado. Tente. :-)
Karen Zilles
1
Ps .successagora está obsoleto. Use em seu .thenlugar. docs.angularjs.org/api/ng/service/$http
redfox05
4

esta resposta me ajudou muito e me indicou a direção certa, mas o que funcionou para mim, e espero que para outros, é:

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
fonte
6
você não deveria estar fazendo algo assim dentro de um serviço?
Katana24
Nunca faça isso em um controlador! ruim! Você deve ter isso escrito como um serviço. Embora a maneira como você chamou o valor json não esteja errada, você deve ter um Service retornando a promessa de não fazer isso no controlador. Do ponto de vista da reutilização, isso é horrível. Por exemplo, você está executando e $ http.get () toda vez que carrega o controlador em vez de ter uma versão em cache da chamada em um serviço.
Downpour046 de
1

Eu tenho aproximadamente esses problemas. Preciso depurar o aplicativo AngularJs do Visual Studio 2013.

Por padrão, o IIS Express restringe o acesso a arquivos locais (como json).

Mas, primeiro: JSON tem sintaxe JavaScript.

Segundo: arquivos javascript são permitidos.

Então:

  1. renomeie JSON para JS ( data.json->data.js).

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

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

Em seguida, use os dados carregados de maneira usual. É apenas uma solução alternativa, é claro.

Alex Sam
fonte
1

++ Isso funcionou para mim. É vanilla javascirptbom para casos de uso, como desordem ao testar com a 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 é o seu javascriptarquivo que contém os JSONdados

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

Por fim, trabalhe com os dados JSON em qualquer lugar do seu código

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

Nota: - Isso é ótimo para teste e até karma.conf.jsaceita esses arquivos para execução de testes, conforme mostrado abaixo. Além disso, eu recomendo isso apenas para organizar dados e testing/developmentambiente.

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

Espero que isto ajude.

++ Baseado nesta resposta https://stackoverflow.com/a/24378510/4742733

ATUALIZAR

Uma maneira mais fácil que funcionou para mim é incluir um functionna parte inferior do código retornando qualquer coisa 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
fonte