AngularJS:工厂 $http.get JSON 文件

Posted

技术标签:

【中文标题】AngularJS:工厂 $http.get JSON 文件【英文标题】:AngularJS: factory $http.get JSON file 【发布时间】:2013-05-31 14:17:00 【问题描述】:

我希望仅使用硬编码的 JSON 文件进行本地开发。我的 JSON 文件如下(放入 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" 
            ]
        
    ]

当 JSON 在工厂内被硬编码时,我的控制器、工厂和 html 都可以正常工作。但是,既然我已经用 $http.get 代码替换了 JSON,它就不起作用了。我已经看到了很多 $http 和 $resource 的不同示例,但不知道该去哪里。我正在寻找最简单的解决方案。我只是想为 ng-repeat 和类似指令提取数据。

工厂:

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

感谢任何和所有帮助。谢谢!

【问题讨论】:

不行吗?它有什么作用?它会抛出错误吗? javascript 控制台中是否有任何输出? 控制台只是说“加载资源失败”,然后有 console.json 文件路径。所以由于某种原因它没有加载它。我的工厂和 JSON 与您在上面看到的完全一样。当我将 JSON 硬编码到工厂中时,它就可以工作了。 您使用什么作为后端? NodeJs 还是一个简单的基于 python 的服务器或其他东西? 我只是想开发不包括后端(Rails)。所以 JSON 只是一个 .json 文件,上面的数据是硬编码的。大概类似于后端将呈现的内容。 您可能不需要响应中的“.data”.. 更改为 --“return response;”,除非您返回的 JSON 捆绑在“data”对象中。 【参考方案1】:

好的,以下是要调查的事项列表:

1) 如果您没有运行任何类型的网络服务器而只是使用 file://index.html 进行测试,那么您可能会遇到同源策略问题。见:

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

许多浏览器不允许本地托管的文件访问其他本地托管的文件。 Firefox 确实允许这样做,但前提是您正在加载的文件包含在与 html 文件(或子文件夹)相同的文件夹中。

2) $http.get() 返回的成功函数已经为你拆分了结果对象:

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

所以用function(response)调用success并返回response.data是多余的。

3) 成功函数不会返回你传递给它的函数的结果,所以这不会像你认为的那样做:

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

这更接近您的预期:

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

4) 但是你真正想做的是返回一个对象的引用,该对象的属性将在数据加载时填充,所以像这样:

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 会从 null 开始,当数据加载时,它会指向它。

或者,您可以返回 $http.get 返回的实际承诺并使用它:

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

然后您可以在控制器的计算中异步使用该值:

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

【讨论】:

嘿,这是一个响应和一个角度相同的 $http 课程 - 很好的答案! 在 4) 下的解释中,在 $http.get() 解决之前不会调用“返回 obj”吗?只是问,因为我认为这就是发生在我身上的事情。 会的。但是当 $http.get() 被解析时调用的闭包保留了对 'obj' 的引用。它将填写您可以使用的内容属性。 使用#3 的第二种形式比使用#4 有什么问题? 链式回调 .success() 已被弃用。请改用 .then(success, error)。【参考方案2】:

++ 这对我有用。它是vanilla javascirpt,适用于使用ngMocks 库进行测试时进行整理等用例:

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

这是您的 javascript 文件,其中包含 JSON 数据

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

最后,在代码中的任何位置使用 JSON 数据

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

注意:- 这非常适合测试,甚至karma.conf.js 也接受这些文件来运行测试,如下所示。另外,我建议仅在整理数据和testing/development 环境时使用此方法。

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

希望这会有所帮助。

++建立在这个答案https://***.com/a/24378510/4742733

之上

更新

对我来说更简单的方法是在代码底部添加一个function,返回任何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"
   

【讨论】:

【参考方案3】:

我想指出 Accepted Answer 的第四部分是错误的 .

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

@Karl Zilles 编写的上述代码将失败,因为obj 将始终在接收数据之前返回(因此值将始终为null),这是因为我们正在进行异步调用。

类似问题详情在this post讨论


在Angular中,当你想进行异步调用时,使用$promise来处理获取的数据。

最简单的版本是

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

我不使用successerror的原因是我刚刚从doc中发现的,这两种方法已被弃用。

$http 旧式 promise 方法成功和错误已被弃用。请改用标准的then 方法。

【讨论】:

在工厂使用return $http.get('content.json');,否则返回null。 嘿,请注意。它起作用的原因(与您在此处的回答相反)是您正在返回对对象的引用。成功函数也引用了同一个对象。当 ajax 函数最终返回时,它会更新返回的原始对象中的“内容”属性。试试吧。 :-) 附言。 .success 现在已弃用。请改用.then。 docs.angularjs.org/api/ng/service/$http【参考方案4】:

我有大约这些问题。我需要从 Visual Studio 2013 调试 AngularJs 应用程序。

默认情况下,IIS Express 限制对本地文件(如 json)的访问。

但是,首先:JSON 具有 JavaScript 语法。

第二:允许使用javascript文件。

所以:

    将 JSON 重命名为 JS (data.json-&gt;data.js)。

    正确的加载命令($http.get('App/data.js').success(function (data) ...

    将脚本 data.js 加载到页面 (&lt;script src="App/data.js"&gt;&lt;/script&gt;)

接下来以通常的方式使用加载的数据。当然,这只是一种解决方法。

【讨论】:

【参考方案5】:

这个答案对我有很大帮助,并为我指明了正确的方向,但对我和希望其他人有用的是:

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

【讨论】:

你不应该在服务中做这样的事情吗? 永远不要在控制器中这样做!坏的!你应该把它写成服务。尽管您调用 json 值的方式没有错,但您应该有一个服务返回承诺,而不是在控制器中执行此操作。从可重用性的角度来看,这也是可怕的。例如,您每次加载控制器时都在执行 $http.get() ,而不是在服务中使用缓存版本的调用。

以上是关于AngularJS:工厂 $http.get JSON 文件的主要内容,如果未能解决你的问题,请参考以下文章

如何从AngularJS获得响应$ http.get()。then()

AngularJS $http.get 不检索后端数据

如何在 AngularJS 中正确使用 HTTP.GET?具体来说,对于外部 API 调用?

TypeScript/angularJS HTTP GET 请求中的范围

angular js:是不是需要在模块文件中加载所有控制器和工厂/服务

Angularjs学习笔记----与后端服务器通信