2016-03-22 11 views
0

私は、ユーザーがアーティストとアルバムのリストを保持できるようにプロジェクトを構築していますが、そのようなものにマッチする先行/自動補完が必要でした。私はlast.fmの先頭からインスピレーションを受けました。Angular js factoryは404エラーで何も返さない

私のHTMLコード:

<!DOCTYPE html> 
<html class="js flexbox flexboxlegacy canvas canvastext webgl no-touch geolocation postmessage websqldatabase indexeddb hashchange history draganddrop websockets rgba hsla multiplebgs backgroundsize borderimage borderradius boxshadow textshadow opacity cssanimations csscolumns cssgradients cssreflections csstransforms csstransforms3d csstransitions fontface generatedcontent video audio localstorage sessionstorage webworkers applicationcache svg inlinesvg smil svgclippaths ng-scope" ng-app="ymusica"><!--<![endif]--><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 

     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> 
     <title>ymusica</title> 
     <meta name="description" content=""> 
     <meta name="viewport" content="width=device-width"> 

     <link rel="stylesheet" href="lib/css/bootstrap.css"> 
     <link rel="stylesheet" href="lib/css/main.css"> 
     <script src="lib/js/modernizr.js"></script> 
    <style type="text/css">@charset "UTF-8";[ng\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none;}ng\:form{display:block;}</style></head> 
    <body> 
     <!--[if lt IE 7]> 
      <p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> or <a href="http://www.google.com/chromeframe/?redirect=true">activate Google Chrome Frame</a> to improve your experience.</p> 
     <![endif]--> 

     <div class="container"> 
      <div ng-controller="AlbumSearch" class="album-search text-center" ng-cloak> 
       <typeahead class="typeahead" items="music" term="term" search="searchMusic(term)" select="selectMusic(item)"> 
        <div class="menu" ng-cloak> 
         <h3 ng-show="hasAlbums()">Albums</h3> 
         <ul> 
          <li typeahead-item="album" ng-repeat="album in albums" class="results"> 
           <img ng-src="{{imageSource(album)}}"><p class="name">{{album.name}}</p><p class="artist">{{album.artist}}</p> 
          </li> 
         </ul> 
         <h3 ng-show="hasArtists()">Artists</h3> 
         <ul> 
          <li typeahead-item="artist" ng-repeat="artist in artists" class="results"> 
           <img ng-src="{{imageSource(artist)}}"><p class="name">{{artist.name}}</p> 
          </li> 
         </ul> 
        </div> 
       </typeahead> 
      </div> 
     </div> 

     <script src="lib/js/jquery.js"></script> 
     <script src="lib/js/rx.js"></script> 
     <script src="lib/js/rx.time.js"></script> 
     <script src="lib/js/rx.coincidence.js"></script> 
     <script src="lib/js/angular.js"></script> 
     <script src="lib/js/module.js"></script> 
     <script src="lib/js/ymusica.js"></script> 
     <script src="lib/js/controller.js"></script> 
     <script src="lib/js/service.js"></script> 
     <script src="lib/js/typeahead.js"></script> 
     <script src="lib/js/angular-resource.js"></script> 
     <script src="lib/js/bootstrap.js"></script> 


     </body> 
</html> 

私のコントローラコード:

angular.module('ymusica').controller('AlbumSearch', ['$scope', 'Albums', 'Artists', '$q', function($scope, albums, artists, $q) { 

$scope.albums = []; 
$scope.artists = []; 

var watchToObservable = function(scope, expression) { 
    var observable = new Rx.Subject(); 

    scope.$watch(expression, observable.onNext.bind(observable)); 

    return observable; 
} 

var functionToObservable = function(scope, name) { 

    var observable = new Rx.Subject(); 

    scope[name] = function(value) { 
     observable.onNext(value); 
    }; 

    return observable; 
} 

var terms = functionToObservable($scope, 'searchMusic'); 

terms.sample(250) 
    .select(function(term) { 
     var promise = $q.all([albums.query(term), artists.query(term)]); 
     return Rx.promiseToObservable(promise) 
    }) 
    .switchLatest() 
    .select(function(promise) { return [promise[0].data.albums, promise[1].data.artists]; }) 
    .subscribe(function(result) { 
     $scope.albums = result[0].slice(0, 5); 
     $scope.artists = result[1].slice(0, 5); 
     $scope.music = $scope.albums.concat($scope.artists); 
    }); 

$scope.selectMusic = function(item) { 
    console.log('music selected!', item); 
    $scope.term = item.name; 
}; 

$scope.imageSource = function(item) { 
    return item.images['medium']; 
}; 

$scope.hasAlbums = function() { 
    return $scope.albums.length > 0; 
}; 

$scope.hasArtists = function() { 
    return $scope.artists.length > 0; 
}; 

}]); 

マイservice.jsコード:

angular.module('ymusica').factory('Albums', ['$http', function($http) { 
return { 
    query: function(term) { 
     return $http.get('/api/album', { params: { q: term } }); 
    } 
    }; 
}]); 

angular.module('ymusica').factory('Artists', ['$http', function($http) { 
return { 
    query: function(term) { 
     return $http.get('/api/artist', { params: { q:term } }); 
    } 
    }; 
}]); 

し、最終的に

マイtypeahead.jsコード(指令):

angular.module('ymusica').directive('typeahead', ["$timeout", function($timeout) { 
return { 
    restrict: 'E', 
    transclude: true, 
    replace: true, 
    template: '<div><form><input ng-model="term" ng-change="query()" type="text" autocomplete="off" /></form><div ng-transclude></div></div>', 
    scope: { 
     search: "&", 
     select: "&", 
     items: "=", 
     term: "=" 
    }, 
    controller: ["$scope", function($scope) { 
     $scope.items = []; 
     $scope.hide = false; 

     this.activate = function(item) { 
      $scope.active = item; 
     }; 

     this.activateNextItem = function() { 
      var index = $scope.items.indexOf($scope.active); 
      this.activate($scope.items[(index + 1) % $scope.items.length]); 
     }; 

     this.activatePreviousItem = function() { 
      var index = $scope.items.indexOf($scope.active); 
      this.activate($scope.items[index === 0 ? $scope.items.length - 1 : index - 1]); 
     }; 

     this.isActive = function(item) { 
      return $scope.active === item; 
     }; 

     this.selectActive = function() { 
      this.select($scope.active); 
     }; 

     this.select = function(item) { 
      $scope.hide = true; 
      $scope.focused = true; 
      $scope.select({item:item}); 
     }; 

     $scope.isVisible = function() { 
      return !$scope.hide && ($scope.focused || $scope.mousedOver); 
     }; 

     $scope.query = function() { 
      $scope.hide = false; 
      $scope.search({term:$scope.term}); 
     } 
    }], 

    link: function(scope, element, attrs, controller) { 

     var $input = element.find('form > input'); 
     var $list = element.find('> div'); 

     $input.bind('focus', function() { 
      scope.$apply(function() { scope.focused = true; }); 
     }); 

     $input.bind('blur', function() { 
      scope.$apply(function() { scope.focused = false; }); 
     }); 

     $list.bind('mouseover', function() { 
      scope.$apply(function() { scope.mousedOver = true; }); 
     }); 

     $list.bind('mouseleave', function() { 
      scope.$apply(function() { scope.mousedOver = false; }); 
     }); 

     $input.bind('keyup', function(e) { 
      if (e.keyCode === 9 || e.keyCode === 13) { 
       scope.$apply(function() { controller.selectActive(); }); 
      } 

      if (e.keyCode === 27) { 
       scope.$apply(function() { scope.hide = true; }); 
      } 
     }); 

     $input.bind('keydown', function(e) { 
      if (e.keyCode === 9 || e.keyCode === 13 || e.keyCode === 27) { 
       e.preventDefault(); 
      }; 

      if (e.keyCode === 40) { 
       e.preventDefault(); 
       scope.$apply(function() { controller.activateNextItem(); }); 
      } 

      if (e.keyCode === 38) { 
       e.preventDefault(); 
       scope.$apply(function() { controller.activatePreviousItem(); }); 
      } 
     }); 

     scope.$watch('items', function(items) { 
      controller.activate(items.length ? items[0] : null); 
     }); 

     scope.$watch('focused', function(focused) { 
      if (focused) { 
       $timeout(function() { $input.focus(); }, 0, false); 
      } 
     }); 

     scope.$watch('isVisible()', function(visible) { 
      if (visible) { 
       var pos = $input.position(); 
       var height = $input[0].offsetHeight; 

       $list.css({ 
        top: pos.top + height, 
        left: pos.left, 
        position: 'absolute', 
        display: 'block' 
       }); 
      } else { 
       $list.css('display', 'none'); 
      } 
     }); 
    } 
    }; 
}]); 

angular.module('ymusica').directive('typeaheadItem', function() { 
return { 
    require: '^typeahead', 
    link: function(scope, element, attrs, controller) { 

     var item = scope.$eval(attrs.typeaheadItem); 

     scope.$watch(function() { return controller.isActive(item); }, function(active) { 
      if (active) { 
       element.addClass('active'); 
      } else { 
       element.removeClass('active'); 
      } 
     }); 

     element.bind('mouseenter', function(e) { 
      scope.$apply(function() { controller.activate(item); }); 
     }); 

     element.bind('click', function(e) { 
      scope.$apply(function() { controller.select(item); }); 
     }); 
    } 
}; 
}); 

私はlast.fm apiも使用しています。問題を解決するのを手伝ってください。オリジナルのlast.fmコードは正常に動作していますが、同じapiパスが使用されていますが、私のコードは404エラーを返します。

答えて

0

あなたがあなた自身のドメインからの代わりに、ここではLast.fmのサーバーからURL /api/artistを取得しようとしているようだ:

return $http.get('/api/artist', { params: { q:term } }) 
私はそれを読んでください_think_: return $http.get('https://last.fm/api/artist', { params: { q:term }});

docsは、次のように表しています。

The API root URL is located at http://ws.audioscrobbler.com/2.0/

また、パラメータを使用して/api/artistを検索するエンドポイントは表示されませんが、search endpointsがあります。

+0

これは私にこのエラーを与えます:https://last.fm/api/album?q=ma net :: ERR_INSECURE_RESPONSE – Sumanta736

+0

@ Sumanta736答えを更新しました。 –

+0

だから、私はAPIのパスと検索の終点を修正するために何をすべきですか? – Sumanta736