I am trying to make an app to do a basic search for youtube videos. I'm using the Youtube Data API and I went to the google developer's console and created a client ID for my domain name.
I downloaded the auth.js and the search.js that Google has on their sample code section and put my client ID into where it says 'my client id' but the application isn't working. I used console.log and it seems that I'm not getting past the function 'checkAuth'.
Am I missing something?? Here is a link to the page: http://www.vidme.cassandraburnscreative.com/#search
Here is the auth.js and search.js together
var OAUTH2_CLIENT_ID = 'my client ID';
var OAUTH2_SCOPES = [
'https://www.googleapis.com/auth/youtube'
];
googleApiClientReady = function() {
console.log("googleApiClientReady");
gapi.auth.init(function() {
window.setTimeout(checkAuth, 1);
console.log("gapi.auth.init");
});
}
function checkAuth() {
gapi.auth.authorize({
client_id: OAUTH2_CLIENT_ID,
scope: OAUTH2_SCOPES,
immediate: true
}, handleAuthResult);
console.log("checkAuth");
}
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
// Authorization was successful. Hide authorization prompts and show
// content that should be visible after authorization succeeds.
$('.pre-auth').hide();
$('.post-auth').show();
loadAPIClientInterfaces();
console.log("Load Interfaces");
} else {
$('#login-link').click(function() {
console.log("nope");
gapi.auth.authorize({
client_id: OAUTH2_CLIENT_ID,
scope: OAUTH2_SCOPES,
immediate: false
}, handleAuthResult);
console.log("HandleAuthResult");
});
}
}
function loadAPIClientInterfaces() {
gapi.client.load('youtube', 'v3', function() {
handleAPILoaded();
console.log("handleAPILoaded");
});
}
function handleAPILoaded() {
$('#search-button').attr('disabled', false);
}
function search() {
var q = $('#query').val();
var request = gapi.client.youtube.search.list({
q: q,
part: 'snippet'
});
request.execute(function(response) {
var str = JSON.stringify(response.result);
$('#search-container').html('<pre>' + str + '</pre>');
});
}
and the html
<div class="wrapper">
<div id="buttons">
<p>Search For an Artist:</p>
<label> <input id="query" placeholder='+ Add Artist' type="text"/>
<button id="search-button" disabled onclick="search()">Search</button>
</label>
</div>
<div id="search-container">
</div>
</div>
You don't need to be connected or use Oauth2 to search something with the YouTube API.
You only need an api key.
A sample example :
function googleApiClientReady() {
var apiKey = 'YOUR_API_KEY';
gapi.client.setApiKey(apiKey);
gapi.client.load('youtube', 'v3', function() {
isLoad = true;
});
request = gapi.client.youtube.search.list({
q: q,
part: 'snippet'
});
request.execute(function(response) {
//your code to here
});
}
Don't forget to add this file to your index.html and add this following line after :
<script src="https://apis.google.com/js/client.js?onload=googleApiClientReady"></script>
From doc YouTube API
Related
How can I check if the user has the default image (eg. image.isDefault result) when logging someone in through the Google API. I'm using getBasicProfile() to retrieve the id, name, email, imageUrl... etc.
Code source
<html>
<head>
<script src="https://apis.google.com/js/api:client.js"></script>
<script>
var googleUser = {};
var startApp = function() {
gapi.load('auth2', function(){
auth2 = gapi.auth2.init({
client_id: 'YOUR_CLIENT_ID.apps.googleusercontent.com',
cookiepolicy: 'single_host_origin',
// Request scopes in addition to 'profile' and 'email'
//scope: 'additional_scope'
});
attachSignin(document.getElementById('customBtn'));
});
};
function attachSignin(element) {
console.log(element.id);
auth2.attachClickHandler(element, {},
function(googleUser) {
var profile = googleUser.getBasicProfile();
var response = {};
response.id = profile.getId();
response.name = profile.getName();
response.first_name = profile.getGivenName();
response.last_name = profile.getFamilyName();
response.image_url = profile.getImageUrl();
response.email = profile.getEmail();
console.log(response);
//******* HOW TO GET THE "image.isDefault" RESULT? ******
}, function(error) {
alert(JSON.stringify(error, undefined, 2));
});
}
</script>
</head>
<body>
<div id="gSignInWrapper">
<span class="label">Sign in with:</span>
<div id="customBtn" class="customGPlusSignIn">
<span class="icon"></span>
<span class="buttonText">Google</span>
</div>
</div>
<div id="name"></div>
<script>startApp();</script>
</body>
</html>
This is the object I'm looking for:
ageRange: Object
min: 21
circledByCount: 0
displayName: "John Smith"
etag: ""FT7asdjf83294289sf/sh-UjzBIkCHasfdj283429sf""
id: "1127384729842983928"
image:
isDefault: true
url: "https://lh3.googleusercontent.com/-XYuefSD/AAAAAAAAAAI/AAAAAAAAAAA/23visd238/photo.jpg?sz=50"
isPlusUser: true
kind: "plus#person"
language: "en"
name:
familyName: "Smith"
givenName: "John"
objectType: "person"
url: "https://plus.google.com/118948298492849237"
verified: false
Here is my answer:
var googleUser = {};
//This method sets up the sign-in listener after the client library loads.
var startApp = function() {
gapi.load('auth2', function(){
gapi.client.load('plus','v1').then(function() {
// Retrieve the singleton for the GoogleAuth library and set up the client.
auth2 = gapi.auth2.init({
client_id: 'YOUR_CLIENT_ID.apps.googleusercontent.com',
cookiepolicy: 'single_host_origin'
//scope: 'additional_scope'
});
attachSignin(document.getElementById('custom-google-btn'));
});
});
};
function attachSignin(element) {
auth2.attachClickHandler(element, {},
function(googleUser) {
var authResult = gapi.auth2.getAuthInstance();
if (authResult.isSignedIn.get()) {
gapi.client.plus.people.get({
'userId': 'me'
}).then(function(res) {
var profile = res.result;
console.log(profile);
//******All the image data is available here******
console.log(profile.image.isDefault);
});
} else {
//alert('not signed in');
if (authResult['error'] || authResult.currentUser.get().getAuthResponse() == null) {
// There was an error, which means the user is not signed in.
// As an example, you can handle by writing to the console:
console.log('There was an error: ' + authResult['error']);
}
}
}, function(error) {
//alert(JSON.stringify(error, undefined, 2));
});
}
I got the next controller:
.controller('LogInController', function(logInFactory, $scope, $location, $state){
$scope.logIn = function() {
$scope.dataLoading = true;
logInFactory.logIn($scope.email, $scope.password, function (response) {
if (response.success) {
$scope.userName = response.userName;
console.log('userName', $scope.userName);
logInFactory.setCredentials($scope.email, $scope.password);
$location.path('/users');
} else {
$scope.dataLoading = false;
}
});
};
$scope.clearCredentials = function(){
$state.go('login');
logInFactory.clearCredentials();
};
});//End controller
I want to use it in this view:
<div class="header" ng-controller = 'LogInController'>
<img src= "logo.jpg">
{{userName}}
<button ng-click = 'clearCredentials()'> Cerrar sesión</button>
</div>
But userName is not showing in the view but when I print it on the controller it is displayed correctly. That view is displayed after call the logIn() function.
This is the logIn function in my factory:
var logIn = function(email, password, callback){
var URL;
if(ENV.mocksEnable){
URL = ENV.apiMock + ENV.logInMock;
return (
$timeout(function () {
var response;
getUser()
.then(function (user) {
console.log('USER', user);
if (user !== null) {
response = { success: true, userName: user.userName};
} else {
response = { success: false, message: 'Username or password is incorrect' };
}
callback(response);
});
}, 1000)
);
}else{
URL = ENV.apiURL + ENV.logIn;
return (
$http.post(URL, {email : email, password : password})
.then(function onFulfilled(response){
var data = response.data;
userName = data.username;
userEmail = data.email;
userId = data.id;
profiles = data.profiles;
callback(response);
return data;
})
.catch(function onRejected(errorResponse){
console.log('Error in logInFactory');
console.log('Status: ', errorResponse.status);
callback(errorResponse);
return errorResponse;
})
);
}
};//End login
I trigger the logIn() function in this view
<form ng-submit = 'logIn()'>
<h1>Log In</h1>
Correo electrónico:
<input type="email" ng-model='email' required><br>
Contraseña
<input type="password" ng-model='password' required><br>
<input type="submit" value="Log in">
</form>
When I tigger logIn() I should go to that header and show the userName.
why are you triggering clearCredentials() ? whereas according to this code you should triggering login() instead.
The result of your logIn() function may be out of Angular scope.
Try wrapping the result of the logIn function into a $timeout (which calls $apply, a way to force Angular to refresh a controller scope):
$timeout(function() {
if (response.success) {
$scope.userName = response.userName;
console.log('userName', $scope.userName);
logInFactory.setCredentials($scope.email, $scope.password);
$location.path('/users');
} else {
$scope.dataLoading = false;
}
});
Do not forget to inject the dependency $timeout in your controller.
You have $scope.userName inside the success of the logIn method. It won't be available until that has happened.
If you put $scope.userName outside of the method and set it to something, it would appear.
.controller('LogInController', function(logInFactory, $scope, $location, $state) {
$scope.userName = 'test name';
$scope.logIn = function() { ...
Something like that.
we don't have your factory code but this line is very strange to me :
logInFactory.logIn($scope.email, $scope.password, function (response) { ..; } )
so your passing the fonction to the factory and it is not the factory who returning data to the controller.
it should be something like this :
logInFactory.logIn($scope.email, $scope.password).then(function (response) { ..; } );
EDIT :
You have to remove the callback function from your factory and make the factory return data and handle data like this logInFactory.logIn($scope.email, $scope.password).then(function (response) { ..; } );.
You have log in the console but the $scope is not shared between the factory and controller so the callback in your factory edit the $scope.userName but the controller cannot get this change.
My problem was that I was expecting to get data from a controller to two different views. And when I go from LogIn view to my header view, the controller refresh its data. So, I have to create in my factory:
var getUserName = function() {
return userName;
};
And in the controller
$scope.userName = logInFactory.getUserName();
Now my userName persists in the factory.
I'm new at angular and if my question is kinda low lvl dont be angry with me.
I have web service which returns sessionId and login success message if user will pass auth. for example url is that:
http://localhost:8181/login?username=USERNAME&password=12345
and here's my response:
{"sessionId":"0997cec2a8b34c84ba8419ab1204e6aa","loginSucceeded":true}
here's my login controller:
app.controller('loginCtrl', function($scope, loginService){
$scope.login=function(user){
loginService.login(user);
}
});
and here's my service:
app.factory('loginService', function($http){
return{
login: function(user){
var $promise=$http.post('http://localhost:8181/login?', user);
$promise.then(function(msg){
if(msg.loginSucceeded=="true")
console.log("opa")
else
console.log("den");
});
}
}
});
and I have user.username and user.password in my scope (using textboxes).
How can I pass those parameters in url and how can I parse that response?
In your code you're passing the username and password in the URL of the POST request. If that's what you really want (it's more common to pass them as POST data) than you can use this:
login: function(user){
var url = 'http://localhost:8181/login?username=' + user.name + '&password=' + user.password;
$http.post(url).then(function(msg){
if(msg.loginSucceeded==="true"){
console.log("opa")
}else{
console.log("den");
}
});
}
If you want to pass the data as POST data, you can pass that as the second argument in the $http.post() call:
login: function(user){
var url = 'http://localhost:8181/login';
var data = {username: user.name, password: user.password};
$http.post(url, data).then(function(msg){
if(msg.loginSucceeded==="true"){
console.log("opa")
}else{
console.log("den");
}
});
};
I never seen anyone passing login data via query string,
if you are in simple http protocol... you should consider using Basic Access Authentication or oAuth...
by the way, if you need to do what described above... this could be help you!
angular
.module('test', [])
.service('LoginService', function($q, $http) {
var self = this;
self.login = function(username, password) {
var configs = { cache: false };
var payload = {
"username" : username,
"password" : password
};
// The Method Post is generally used with a payload, but if you need to pass it as query string... you have to do:
configs.params = payload;
return $http
.post('/api/login', null /* but normally payload */, configs)
.then(function(result) {
console.log('LoginService.login:success', result);
return result.data;
})
.catch(function(error) {
console.log('LoginService.login:error', error);
return $q.reject(error);
});
;
};
})
.controller('LoginCtrl', function(LoginService, $scope) {
var vm = $scope
vm.username = 'hitmands';
vm.password = 'helloWorld';
vm.debug = 'CIAO';
vm.onFormSubmit = function(event, form) {
if(form.$invalid) {
event.preventDefault();
return;
}
vm.debug = null;
return LoginService
.login(vm.username, vm.password)
.then(function(data) { vm.debug = data; })
.catch(function(error) { vm.debug = error; })
;
};
})
;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<article ng-app="test">
<div ng-controller="LoginCtrl">
<form ng-submit="onFormSubmit($event, loginForm);" name="loginForm">
<input type="text" placeholder="username" ng-model="username">
<input type="password" placeholder="Password" ng-model="password">
<div>
<button type="submit">Send Login Data</button>
</div>
<div style="color: blue; padding: 1em .5em;" ng-bind="debug | json">
</div>
</form>
</div>
</article>
I have a custom directive for soundcloud that requires the soundcloud url. The soundcloud url is fetched from the database through the $http service, however, the div for the soundcloud custom directive is loaded and requires the value of the soundcloud url before it is even defined.
The Plangular Directive Code I got is here:
https://github.com/jxnblk/plangular/blob/master/src/plangular.js *I did not develop this
This is my HTML code:
<div plangular="{{soundcloud}}">
<button ng-click="playPause()">Play/Pause</button>
<progress ng-value="currentTime / duration || 0">
{{ currentTime / duration || 0 }}
</progress>
</div>
And this is the Angular Code:
displaySong.controller('song', ['$scope', '$http', 'fetchSong', function($scope, $http, fetchSong) {
$scope.songID
$scope.songName;
//Controller properties
$scope.songPromise; //The song promise for fetching
$scope.init = function(songID, userID) {
$scope.songID = songID;
$scope.userID = userID;
$scope.songPromise = $http({
method: "post",
url: fetchSong,
data: {
song_id: $scope.songID
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).then(function(successResponse) {
console.log('Successfully fetched song');
console.log(successResponse);
var song = successResponse.data;
$scope.songID = song.song_id;
$scope.songName = song.song_name;
$scope.songType = song.song_type;
$scope.songEmbed = song.song_embed;
$scope.soundcloud = song.song_embed;
}, function(errorResponse) {
console.log('Error fetching');
$scope.songID = null;
});
};
}]);
I know it's a problem with the asynchronous nature because when I add this line in the beginning of my song controller:
$scope.soundcloud = "https://soundcloud.com/jshigley/shine";
It works perfectly fine. I've also noticed that when I spam the play/pause button that DOES come up from the directive, I get multiple console errors of "HTTP 404 Not Found", which leads me to believe it's trying to find a track of undefined url
Since it's a div directive and not a function call I can't use promises such as chaining a then to my $scope.songPromise. I've thought of putting it into a controller and having the controller do something like $timeout for 5 seconds, but I don't think this delays the execution of the DOM.
The soundcloud URL DOES end up getting loaded, but it remains undefined in the eyes of the plangular directive (I've actually encountered lots of these problems with bad timing of loading scope and directives). Any Angular Wizards willing to teach me how to tame the asynchronous nature of AngularJS?
You can use $watch in the custom directive to watch when url attributes is changed.
In
link: function(scope, el, attr) {
change from
if (src) {
resolve({ url: src, client_id: client_id }, function(err, res) {
if (err) { console.error(err); }
scope.$apply(function() {
scope.track = createSrc(res);
if (Array.isArray(res)) {
scope.tracks = res.map(function(track) {
return createSrc(track);
});
} else if (res.tracks) {
scope.playlist = res;
scope.tracks = res.tracks.map(function(track) {
return createSrc(track);
});
}
});
});
}
to
scope.$watch('attr.plangular', function(newVal) {
resolve({ url: attr.plangular, client_id: client_id }, function(err, res) {
if (err) { console.error(err); }
scope.$apply(function() {
scope.track = createSrc(res);
if (Array.isArray(res)) {
scope.tracks = res.map(function(track) {
return createSrc(track);
});
} else if (res.tracks) {
scope.playlist = res;
scope.tracks = res.tracks.map(function(track) {
return createSrc(track);
});
}
});
});
}, true);
If you dont want to change the directive then you might want to use ng-if to load that plangular div only when you get the url.
<div plangular="{{soundcloud}}" ng-if="haveurl">
and in the angular code :
}).then(function(successResponse) {
console.log('Successfully fetched song');
console.log(successResponse);
$scope.haveurl = true;
Try using ng-show like this to only show the div once your $http request has been completed.
<div ng-show="httpRequestComplete" plangular="{{soundcloud}}">
<button ng-click="playPause()">Play/Pause</button>
<progress ng-value="currentTime / duration || 0">
{{ currentTime / duration || 0 }}
</progress>
</div>
displaySong.controller('song', ['$scope', '$q', '$http', 'fetchSong', function($scope, $http, fetchSong) {
/* add $q promise library */
$scope.songID
$scope.songName;
var httpRequest = function() {
var deferred = $q.defer();
$http({
method: "post",
url: fetchSong,
data: {
song_id: $scope.songID
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).success(function(successResponse) {
deferred.resolve({response: successResponse});
console.log('Successfully fetched song', successResponse);
var song = successResponse.data;
$scope.songID = song.song_id;
$scope.songName = song.song_name;
$scope.songType = song.song_type;
$scope.songEmbed = song.song_embed;
$scope.soundcloud = song.song_embed;
}).error(function(error) {
console.log(error);
});
return deferred.promise;
};
httpRequest().then(function(response) {
$scope.httpRequestComplete = true;
console.log('div will show');
};
}]);
I would do something like this that delays the showing of the div until httpRequestComplete = true, or until your promise ($q) is fulfilled. This will make sure that your div isn't loaded until you have the information available.
I am trying to get events from my calendar by using the Google API:
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="googleCalendar.js"></script>
<script src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
</head>
<body>
<div id="calendarContainer">
<div>
<button type="button" id="authorize-button"><?= _("Google Calendar Events"); ?></button>
</div>
<div id="content">
<h2><?= _("Events"); ?></h2><br>
<ul id="events"></ul>
</div>
</div>
</body>
</html>
googleCalendar.js:
$(document).ready(function() {
var clientId = '{my_client_id}';
var apiKey = '{my_api_key}';
var scopes = 'https://www.googleapis.com/auth/calendar';
$("#authorize-button").click(function(){
handleClientLoad();
});
function handleClientLoad()
{
gapi.client.setApiKey(apiKey);
window.setTimeout(checkAuth,1);
checkAuth();
}
function checkAuth()
{
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: true},
handleAuthResult);
}
function handleAuthResult(authResult)
{
var authorizeButton = document.getElementById('authorize-button');
if (authResult) {
//authorizeButton.style.visibility = 'hidden';
makeApiCall();
} else {
authorizeButton.style.visibility = '';
authorizeButton.onclick = handleAuthClick;
}
}
function handleAuthClick(event)
{
gapi.auth.authorize(
{client_id: clientId, scope: scopes, immediate: false},
handleAuthResult
);
return false;
}
function makeApiCall()
{
gapi.client.load('calendar', 'v3', function() {
var request = gapi.client.calendar.events.list({
'calendarId': 'primary'
});
request.execute(function(resp) {
console.log(resp);
for (var i = 0; i < resp.items.length; i++) {
var li = document.createElement('li');
li.appendChild(document.createTextNode(resp.items[i].summary));
document.getElementById('events').appendChild(li);
}
});
});
}
});
When I click the button in order to get my events I get nothing. Then I inspect my page and I get this:
Request URL:
https://content.googleapis.com/calendar/v3/calendars/primary/events?key={my_api_key}
Status Code: 404 Not found
Pasting that URL in my browser I get this:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "notFound",
"message": "Not Found"
}
],
"code": 404,
"message": "Not Found"
}
}
Why do I get a 404 not found and I don't get the list of events from my calendar?