了解Angular Promises和API调用 - 从API

时间:2017-05-03 03:05:48

标签: javascript angularjs angular-promise github-api angular-http

我正在尝试创建一个模仿here所示功能的简单仪表板。我想要坚持一个棱角分明的构造,但我已经成功地将自己混淆为遗忘。我对Angular一般都是新手。

我正在根据Github API中的数据创建一个简单的仪表板。我想引用以下数据源(其中用户是搜索栏中的值,而 repo 是从回购列表中点击的值 - 请参阅链接示例in第1段):

"https://api.github.com/users/" + user                          ----> returns general user info
"https://api.github.com/users/" + user + "/repos"               ----> used for repo list
"https://api.github.com/repos/" + user + "/" + repo + "/events" ----> list of events per repo

基本上,应用程序应该按以下方式工作:

  1. 用户在搜索栏中输入Github用户名。

  2. 进行API调用以返回用户信息和回购列表     (我列出的前两个网址)

  3. 到目前为止,我有这个工作。

    1. 然后,根据返回的下拉列表中的第一个选定的repo或所选的值,将调用第3个url以返回更多数据。
    2. 据我所知,我需要加入Angular承诺,因为我的第3次Get请求未被识别。

      有人可以帮我重构我的app.js代码,以确保: - 我有一套" repo"页面渲染(即第一个列出的仓库将被默认选中) - 用户与回购列表交互后再次调用事件api

      我试图按照here的说法进行操作,但我对如何合并用户名和选定的回购图感到困惑。如果有人可以告诉我如何在我的代码中添加这些参数(由用户指定),我真的很感激!

      这是我目前的代码,仅供参考:

      app.js

      angular.module('myApp', ['ui.router'])
          .controller('DashboardCtrl', function($scope, $state, $http){
              // Set search model to 'mbostock' and the fetch function to contact the
              // remote API and ensure the view is initialized. Load results when the search box changes.
              $scope.$watch('search', function() {
                  initialFetch();
              });
              $scope.search = "mbostock";
      
      
          // Make calls to the API for Users and Repo List
          function initialFetch(){
              $http.get("https://api.github.com/users/" + $scope.search)
                  .then(function(response){ $scope.userinfo = response.data; });
      
              $http.get("https://api.github.com/users/" + $scope.search + "/repos")
                  .then(
                      function(response){ $scope.repolist = response.data;
      
                      // Create call for events listing based on repo choice
                      var repo = "";
      
                      // console.log(document.getElementById("repo1").value);
      
                      $(function() {
                          //For showing default url
                          MakeUrl();
                          // On repository selection, call events
                          $('#repo-select').on('change', function () {
                              if ($(this).val() == 0) {
                                  repo = document.getElementById("repo1").value;
                              } else {
                                  repo = $(this).val();
                              }
                              MakeUrl();
                              return false;
                          });
      
                      });
      
                      function MakeUrl() {
                          var finalUrl = "https://api.github.com/repos/" + $scope.search + "/" + repo + "/events";
                          console.log(finalUrl);
                          $http.get(finalUrl)
                              .then(function (response) { $scope.eventinfo = response.data; });
                      }
      
      
                      });
          }
      
      
          // Function select which ensures that the entire
          // text is selected when the user clicks in the text input.
          $scope.select = function(){
              this.setSelectionRange(0, this.value.length);
          }
      })
      

      的index.html

      <body>
      <div class="container-fluid outerdiv" ng-app="myApp" ng-controller="DashboardCtrl">
      
          <nav class="navbar navbar-inverse navbar-fixed-top">
              <div class="container-fluid">
                  <div class="navbar-header">
                      <a class="navbar-brand"><b>Github User Information</b> <span class="span-style"></span></a>
                  </div>
      
                  <div class="input-group search-bar">
                      <input type="text" ng-model="search" ng-model-options="{ debounce: 800 }" onclick="select()" class="form-control" placeholder="Enter Github user login" autofocus />
                      <span class="input-group-addon bar-style"><i class="glyphicon glyphicon-search"></i></span>
                  </div>
              </div>
          </nav>
      
          <noscript>
              <div class="nojs">Javascript is either disabled or not supported in your browser. Please enable it or use a Javascript enabled browser.</div>
          </noscript>
      
          <div class="animated zoomInRight">
      
      
              <div id="user-bio" class="col-sm-4 col-md-4">
                  <div>
                      <div class="avatar">
                          <img src="{{ userinfo.avatar_url }}" class="thumbnail animated flip movie-poster">
                      </div>
      
                      <span class="span-outer">
                          <a href="{{userinfo.html_url}}" target="_blank">{{ userinfo.login }}</a>
                      </span><br>{{ userinfo.name }}
      
                      <p><strong>Joined:</strong><br> {{ userinfo.created_at }}</p>
                      <p><strong>Last Updated:</strong><br> {{ userinfo.updated_at }}</p>
      
                      <p>{{ userinfo.bio }}</p>
      
                      <p class="outer-p">
                      <div class="inner-p">
                          <span class="label label-primary">Public Repos :</span> {{ userinfo.public_repos }}
                      </div>
                      <div class="inner-p">
                          <span class="label label-primary">Followers :</span> {{ userinfo.followers }}
                      </div>
                      <div class="inner-p">
                          <span class="label label-primary">Following :</span> {{ userinfo.following }}
                      </div>
                      </p>
      
                  </div>
      
                  <div ng-if="userinfo.message==='Not Found'">
                      No results found.
                  </div>
              </div>
      
              <div class="col-sm-8 col-md-8">
                  <h5><strong>Repositories:</strong></h5>
                  <select id="repo-select">
                      <option ng-repeat="repo in repolist" id="repo{{ $index + 1 }}" value="{{ repo.name }}" onchange="MakeUrl();">{{ repo.name }}</option>
                  </select>
      
                  <h5><strong>Events:</strong></h5>
                  <ul class="event-results" id="event-select" style="height:400px; overflow-y:auto;">
                      <li ng-repeat="event in eventinfo">
                          <a id="{{ $index + 1 }}" value="{{ event.type }}">{{ event.type }}
                          </a>, {{ event.created_at }} <!--ng-click="update(movie)"-->
                      </li>
                  </ul>
              </div>
      
          </div>
      </div>
      
      </body>
      

      修改 这是我看到的错误 - 再次,它们似乎表明我需要实施承诺。然后,我不确定为什么我无法指定默认选定的回购。

      可能未经处理的拒绝:{&#34;数据&#34;:{&#34;消息&#34;:&#34;未找到&#34;,&#34; documentation_url&#34;:&#34; https://developer.github.com/v3&#34;}&#34;状态&#34;:404,&#34;配置&#34; {&#34;方法&#34;:&#34; GET&#34 ;, &#34; transformRequest&#34;:[空],&#34; transformResponse&#34;:[空],&#34; jsonpCallbackParam&#34;:&#34;回调&#34;&#34; URL&# 34;:&#34; https://api.github.com/repos/mbostock//events&#34;,&#34;标题&#34;:{&#34;接受&#34;:&#34; application / json,text / plain, / &#34;}},&#34; statusText&#34;:&#34; Not Found&#34;}

      更新和修改 通过@mikwat的建议,我尝试使用ng-model来绑定repo变量。

      我的新app.js文件如下所示:

      angular.module('myApp', ['ui.router'])
          .controller('DashboardCtrl', function($scope, $state, $http, DataService){
              // Set search model to 'mbostock' and the fetch function to contact the
              // remote API and ensure the view is initialized. Load results when the search box changes.
              $scope.$watch('search', function() {
                  initialFetch();
                      // .then(MakeUrl);
              });
      
              var user = $scope.search;
              $scope.search = "mbostock";
              $scope.repo = "array-source";
      
      
              // Make calls to the API for Users and Repo List
              function initialFetch(){
                  $http.get("https://api.github.com/users/" + $scope.search)
                      .then(function(response){ $scope.userinfo = response.data; });
      
                  $http.get("https://api.github.com/users/" + $scope.search + "/repos")
                      .then(
                          function(response){ $scope.repolist = response.data; },
                          $http.get("https://api.github.com/repos/" + $scope.search + "/" + $scope.repo + "/events")
                              .then(function (response) { $scope.eventinfo = response.data; })
                      );
              }
      
      
              // Function select which ensures that the entire
              // text is selected when the user clicks in the text input.
              $scope.select = function(){
                  this.setSelectionRange(0, this.value.length);
              }
          });
      

      虽然这是要渲染数据,但我无法弄清楚如何动态地将第一个repo列表值分配为我的默认值(我尝试了document.getElementById("repo1").value但是我得到了未定义的数据&#39;)AND该函数不会在下拉列表更改时再次调用API。

      更新5/5/2017 - 个人解决方案 非常感谢@mikwat的所有帮助。我最终使用的解决方案与他下面的解决方案略有不同,但两者都有效。

      angular.module('myApp', [])
      .controller('DashboardCtrl', function($scope, $http){
          // Set search model to 'mbostock' and the fetch function to contact the
          // remote API and ensure the view is initialized. Load results when the search box changes.
          $scope.$watch('search', function() {
              initialFetch();
              // .then(MakeUrl);
          });
      
          // NOTE: watch for changes to repo
          $scope.$watch('repo', function() {
              $http.get("https://api.github.com/repos/" + $scope.search + "/" + $scope.repo + "/events")
                  .then(function (response) {
                      $scope.eventinfo = response.data;
                  });
      
          });
      
          var user = $scope.search;
          $scope.search = "mbostock";
      
          // Make calls to the API for Users and Repo List
          function initialFetch(){
              $http.get("https://api.github.com/events")
                  .then(function(response){ $scope.publicevents = response.data; console.log(response.data);})
                  .catch(function (err) {
                              console.log(err)
                          });
      
              $http.get("https://api.github.com/users/" + $scope.search)
                  .then(function(response){ $scope.userinfo = response.data; })
                  .catch(function (err) {
                              console.log(err)
                          });
      
              $http.get("https://api.github.com/users/" + $scope.search + "/repos")
                  .then(
                      function(response){
                          $scope.repolist = response.data;
      
                          // NOTE: select first repo
                          if ($scope.repolist && $scope.repolist.length > 0) {
                              var repo = $scope.repolist[0].name;
                          } else {
                              console.log("Something went wrong here!");
                              var repo = "undefined"
                          }
                          $scope.repo = repo;
                          return repo
                      }).then(function (repo) { 
                              $http.get("https://api.github.com/repos/" + $scope.search + "/" + repo + "/events")
                              .then(function (response) { $scope.eventinfo = response.data; console.log(response.data);})
                              return repo; 
                          }).then(function (repo) {
                              $http.get("https://api.github.com/repos/" + $scope.search + "/" + repo + "/languages")
                              .then(function (response) { $scope.languages = response.data; console.log(response.data);})
                          }).catch(function (err) {
                              console.log("Here!" + err);
                          });
          };
      
      
          // Function select which ensures that the entire
          // text is selected when the user clicks in the text input.
          $scope.select = function(){
              this.setSelectionRange(0, this.value.length);
          }
      
      
      });
      

1 个答案:

答案 0 :(得分:1)

这是一个有效的解决方案。我删除了一些依赖项,只是为了让它在这个沙箱中工作。我使用NOTE:条评论来帮助描述重要的变化。

angular.module('myApp', [])
    .controller('DashboardCtrl', function($scope, $http){
        // Set search model to 'mbostock' and the fetch function to contact the
        // remote API and ensure the view is initialized. Load results when the search box changes.
        $scope.$watch('search', function() {
            initialFetch();
                // .then(MakeUrl);
        });
        
        // NOTE: watch for changes to repo
        $scope.$watch('repo', function() {
            $http.get("https://api.github.com/repos/" + $scope.search + "/" + $scope.repo + "/events")
                 .then(function (response) {
                     $scope.eventinfo = response.data;
                  });
                  
            // NOTE: additional request to fetch languages
            $http.get("https://api.github.com/repos/" + $scope.search + "/" + $scope.repo + "/languages")
                 .then(function (response) {
                     console.log(response.data);
                     // TODO: display results
                  });

        });

        var user = $scope.search;
        $scope.search = "mbostock";

        // Make calls to the API for Users and Repo List
        function initialFetch(){
            $http.get("https://api.github.com/users/" + $scope.search)
                .then(function(response){ $scope.userinfo = response.data; });

            $http.get("https://api.github.com/users/" + $scope.search + "/repos")
                .then(
                    function(response){
                        $scope.repolist = response.data;
                        
                        // NOTE: select first repo
                        if ($scope.repolist && $scope.repolist.length > 0) {
                            $scope.repo = $scope.repolist[0].name;
                        }
                    },
                    $http.get("https://api.github.com/repos/" + $scope.search + "/" + $scope.repo + "/events")
                        .then(function (response) { $scope.eventinfo = response.data; })
                );
        }


        // Function select which ensures that the entire
        // text is selected when the user clicks in the text input.
        $scope.select = function(){
            this.setSelectionRange(0, this.value.length);
        }
    });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div class="container-fluid outerdiv" ng-app="myApp" ng-controller="DashboardCtrl">

    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container-fluid">
            <div class="navbar-header">
                <a class="navbar-brand"><b>Github User Information</b> <span class="span-style"></span></a>
            </div>

            <div class="input-group search-bar">
                <input type="text" ng-model="search" ng-model-options="{ debounce: 800 }" onclick="select()" class="form-control" placeholder="Enter Github user login" autofocus />
                <span class="input-group-addon bar-style"><i class="glyphicon glyphicon-search"></i></span>
            </div>
        </div>
    </nav>

    <noscript>
        <div class="nojs">Javascript is either disabled or not supported in your browser. Please enable it or use a Javascript enabled browser.</div>
    </noscript>

    <div class="animated zoomInRight">


        <div id="user-bio" class="col-sm-4 col-md-4">
            <div>
                <div class="avatar">
                    <img src="{{ userinfo.avatar_url }}" class="thumbnail animated flip movie-poster">
                </div>

                <span class="span-outer">
                    <a href="{{userinfo.html_url}}" target="_blank">{{ userinfo.login }}</a>
                </span><br>{{ userinfo.name }}

                <p><strong>Joined:</strong><br> {{ userinfo.created_at }}</p>
                <p><strong>Last Updated:</strong><br> {{ userinfo.updated_at }}</p>

                <p>{{ userinfo.bio }}</p>

                <p class="outer-p">
                <div class="inner-p">
                    <span class="label label-primary">Public Repos :</span> {{ userinfo.public_repos }}
                </div>
                <div class="inner-p">
                    <span class="label label-primary">Followers :</span> {{ userinfo.followers }}
                </div>
                <div class="inner-p">
                    <span class="label label-primary">Following :</span> {{ userinfo.following }}
                </div>
                </p>

            </div>

            <div ng-if="userinfo.message==='Not Found'">
                No results found.
            </div>
        </div>

        <div class="col-sm-8 col-md-8">
            <h5><strong>Repositories:</strong></h5>
            
            <!-- NOTE: use ng-model and ng-repeat and don't clobber repo variable on scope -->
            <select id="repo-select" ng-model="repo">
                <option ng-repeat="r in repolist" id="repo{{ $index + 1 }}" ng-value="r.name" onchange="MakeUrl();">{{ r.name }}</option>
            </select>

            <h5><strong>Events:</strong></h5>
            <ul class="event-results" id="event-select" style="height:400px; overflow-y:auto;">
                <li ng-repeat="event in eventinfo">
                    <a id="{{ $index + 1 }}" value="{{ event.type }}">{{ event.type }}
                    </a>, {{ event.created_at }} <!--ng-click="update(movie)"-->
                </li>
            </ul>
        </div>

    </div>
</div>