I am trying to retrieve a reset pw token from a link in an reset pw email. The link sends the user back to my node/angular app with the token which I am trying to get.
Laravel API: email template
<td class="content">
Reset Your Password
</td>
Node/Angular app: ResetPassword.ejs template: I am using an angular controller:
<div ng-controller="resetPasswordCtrl">
...stuff
</div>
reset password Controller:
'use strict';
angular
.module('myApp')
.controller('resetPasswordCtrl', ['$scope', '$routeParams', '$location', function($scope, $routeParams, $location) {
console.log('ROUTE PARAMS', $routeParams); //object with a bunch of getters/setters
console.log('ROUTE PARAMS', $routeParams.token); //undefined
console.log('Location', $location.search('token')); //LocationHashbangUrl
console.log('Location', $location.search().token); //true
console.log('Location', $location.search()['token']); //true
console.log('Route current params', $route); //empty route object
}]);
For the LocationHashbangUrl ($location.search('token')), I know I am getting the correct url with the token because the $$absUrl shows it.
Why am I unable to retrieve the token param using one of those methods shown in the controller?
Can you post your $routeProvider? You could just add token as a parameter there, and then $routeParams.token would do what you want. Something like this:
$routeProvider.when('/reset-password/:token')
That would mean your reset password url would look like this though:
http://localhost:3000/reset-password/{{$token}}
Turns out without using html5/angular routing, the typical methods
$location.search()
$routeParams
will not work.
Since I am passing the params and accessing my node app externally (from the e-mail link distributed from laravel), I needed to parse the URI using javascript.
I found this resource which makes it easy. So, the following works:
'use strict';
angular
.module('myApp')
.controller('resetPasswordCtrl', ['$scope', '$window', function($scope, $route, $window) {
var getURIParams = function(variable) {
var query = $window.location.search.substring(1);
var vars = query.split('&');
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=');
if (decodeURIComponent(pair[0]) == variable) {
return decodeURIComponent(pair[1]);
}
}
console.log('Query variable %s not found', variable);
};
console.log('VAR', getURIParams('token')); //my token param
}]);
Related
How can i check if the id that i get from the url is equal to any of the ids in the json api here is my code
.controller('PlayAod', ['$scope', '$http', '$state', '$stateParams', '$location', function ($scope, $http, $state, $stateParams) {
$scope.title = 'Sample Company';
$scope.apiusername = 'hoy';
$scope.apipassword = '076fdf74936ebae00e7949a80f61f985';
$scope.aodid = $stateParams.ahls;
$scope.stream = "";
$http.get('http://tvstartup.biz/mng-channel/vpanel/api/audios.php?user=' + $scope.apiusername + '&pass=' + $scope.apipassword).success(function (data) {
$scope.aodhls = data.audios;
if (data.audios.id == $scope.aodid) {
$scope.stream = date.audios.hls_stream;
}
});
$scope.play = function() {
window.cndStream.play($scope.stream);
}
$scope.pause = function() {
window.cndStream.pause();
}
}])
please help if you have any questions post in comments
As I have experience with your problem from another question, I will add context for other users that your $http request here returns an array of objects, and each of the objects has a property named 'id'.
Assuming that you are trying to track down the particular object within the array of which object.id == $scope.aodid, you can search over the array until the comparative proves true. One such example would be:
// Inside of $http.get success function
var audioList = data.audios;
for(var audio of audioList) {
if(audio.id == $scope.aodid) {
// Oh, joy this is the one I want!
// Perform some magic...
// Or maybe in your case...
$scope.stream = audio.hls_stream;
// Dont forget to stop searching...
break;
}
}
A potentially better solution would be to provide the ID in the query such that you only get back what you want and don't have to iterate a list, however I am infering a bit as to what you are ultimately trying to do.
I would like to know how to unit test AngularJs $resource query with params.
I have this:
services.js
angular.module('conciergeApp.services', ['ngResource'])
.factory('Reply', function($resource) {
return $resource('/api/reply/:id/');
});
controllers.js
conciergeControllers.controller('ReplyCtrl', ['$scope', 'Reply',
function($scope, Reply) {
$scope.hotel_replies = Reply.query({
hotel: $scope.hotel_id
});
}
]);
So, the API Endpoint that gets queried here is:
'/api/reply/?hotel=<hotel_id>'
// aka
'/api/reply/?hotel=1'
This works when manually tested, but how do you unit test this?
With Jasmine spyOn, or $httpBackend. Whichever would be fine?
Can this be used? I tried this pattern, but couldn't do it successfully:
spyOn(object, 'method').andCallFake(function({foo:bar}) {
return myMockObject
});
Example here using Jasmine 2.0 and htmlRunner. Explanation to follow:
So inside your ReplyCtrl unit test:
describe('ReplyCtrl Controller', function () {
var Reply;
var ReplyCtrl;
var $scope;
var ReplyQueryMock;
var HOTEL_ID = 1234;
beforeEach(module('conciergeApp'));
beforeEach(inject(function (_Reply_, $controller, $rootScope) {
// This object can be used throughout your controller unit test for the
// response of calling the Reply.query method
ReplyQueryMock = {};
Reply = _Reply_;
spyOn(Reply, 'query').and.returnValue(ReplyQueryMock);
$scope = $rootScope.$new();
$scope.hotel_id = HOTEL_ID;
ReplyCtrl = $controller('ReplyCtrl', {$scope: $scope});
}));
it('should populate hotel_replies', function () {
expect(Reply.query).toHaveBeenCalledWith({
hotel: HOTEL_ID
});
expect($scope.hotel_replies).toBe(ReplyQueryMock);
});
});
This will mock out your Reply service and return a mocked object for the query. You will verify that your $scope's hotel_replies is the result of calling Reply.query with the hotel_id that is present on $scope.
Edit: Presumably $resource has been unit tested for you (by Angular team!). You might just want to verify that you setup the resource with the correct URL rather than digging down into the internals of what $resource really does (like calling $http for example). Fiddle link above updated, and would look something like the following:
describe('Reply Resource', function () {
var Reply;
var $resource;
var ReplyResourceMock;
beforeEach(module('conciergeApp.services', function ($provide) {
// Mock out $resource here
$provide.factory('$resource', function () {
ReplyResourceMock = {};
var $resource = jasmine.createSpy('$resource');
$resource.and.returnValue(ReplyResourceMock);
return $resource;
});
}));
beforeEach(inject(function (_Reply_, _$resource_) {
Reply = _Reply_;
$resource = _$resource_;
}));
it('should initialize resource', function () {
expect($resource).toHaveBeenCalledWith('/api/reply/:id/');
expect(Reply).toBe(ReplyResourceMock);
});
});
From original answer, probably overkill since you use $resource to abstract $http (still shown in fiddle)
Then to verify $resource works correctly from your Reply factory/service, you will want to inject $httpBackend. You can verify that the proper REST endpoint is called with the correct data.
My web application login process is as follows,
a. The user clicked on the login button, and the link take them to http://localhost:3030/login/facebook
b. The NodeJS backend receives the request, and with passport-facebook, directs the browser to the Facebook login page.
c. The Facebook then direct the user back to the callback with some user data. (the callback: http://localhost:3030/login/facebook/callback)
d. With the user data, an account either exist or will be created, and a token belonging to the account will be created (with JWT)
e. That token will be sent to the user by redirection to http://localhost:3030/#/got_token/the_actual_jwt_string
f. The AngularJS application will take the route with ngRoute, and save the token in localStorage.
The Token Issue Code in NodeJS,
server.get('/auth/facebook', passport.authenticate('facebook', {session: false}));
server.get('/auth/facebook/callback', passport.authenticate('facebook', {session: false}), function(req, res) {
var token = jwt.sign(/* issue a token */);
// put the token into database
res.header('Location', 'http://localhost:3030/#/got_token/' + token);
res.send(302);
});
The routing code in AngularJS,
.when('/got_token/:token*', {
redirectTo: function(parameters, path, search) {
localStorage.setItem('ngStorage-token', JSON.stringify({
token: parameters.token
}));
return '/';
}
})
This works great until that my view hierarchy looks like this,
<body ng-controller="NavigationViewController">
<div ng-view>
</div>
</body>
And the controller code,
controllers.controller('NavigationViewController', ['$scope', '$route', 'token', function($scope, $route, token) {
var _token = token.retrieve();
$scope.token = _token;
$scope.authenticated = (_token != '');
if ($scope.authenticated) {
var payload_string = b64utos(_token.split('.')[1]);
var payload = KJUR.jws.JWS.readSafeJSONString(payload_string);
$scope.displayName = payload.facebookDisplayName;
} else {
$scope.displayName = 'no';
}
$scope.logout = function() {
token.clear();
};
}]);
The routing done by ngRoute does not recreate my NavigationViewController, leaving the _token variable set to the previous state.
I need a way to have the NavigationViewController know that the token has changed since its not involved in routing.
Would like to suggest you two ideas.Here are these two.
(1.) You can add $watch to the token so that whenever it would be changed it will automatically reflect.
(2.) Assign the token into rootscope and update it whenever the token gets changed.
I would like to give you the examples as well if you would needed.
Regards,
Mahendra
Looks like you need to pass data between controllers. Here's a way you could do it. Listen on an event in your NavigationViewController for changed and emit the event it when it changes. Bind it on rootScope.
angular.module('app', [])
.controller('LoginCtrl', function ($scope, $rootScope) {
$scope.changeToken = function () {
$rootScope.$emit('changed', +new Date());
}
})
.controller('NavigationViewController', function ($scope, $rootScope) {
$scope.token = null;
$rootScope.$on('changed', function(event, token) {
$scope.token = token;
});
})
At the end, a simple solution is used -- Events.
As the title of my problem suggests, I want to reload a nested parent view controller on route change. Since the parent of the nested hierarchy is not managed by ngRoute, it won't do it automagically. However, ngRoute has a service ($route) which emit events, and that is the simplest answer.
Basically, I put all the initialization code to a function, and call that function on event.
controllers.controller('NavigationViewController', ['$scope', '$route', '$location', 'token', function($scope, $route, $location, token) {
var updateNavigationBar = function() {
var _token = token.retrieve();
$scope.token = _token;
$scope.authenticated = (_token != '');
if ($scope.authenticated) {
var payload_string = b64utos(_token.split('.')[1]);
var payload = KJUR.jws.JWS.readSafeJSONString(payload_string);
$scope.displayName = payload.facebookDisplayName;
} else {
$scope.displayName = 'no';
}
};
$scope.$on('$routeChangeSuccess', function(event, current, previous) {
if ($location.path() == '/events') {
updateNavigationBar();
}
});
updateNavigationBar();
}]);
I have been experimenting with a few ways to create this form.
Scotch seemed to have a great tutorial with nested views.
This is the part of the JS file I assume the problems occur.
I created a demo at http://plnkr.co/edit/nNTEI4tBw0XFana1nKIS?p=preview.
.controller('formController', function($scope) {
// we will store all of our form data in this object
$scope.formData = {};
// function to process the form
$scope.processForm = function() {
if ($scope.formData = '"phone":"iphone' &&'"type":"xbox"'){
parent.location='results';
}
};
});
How do I get the submit button to reroute to the results.html?
(I wouldn't be surprised if my JS was less than pristine)
any help would be awesome.
Two things that need to be done. First, if you examine your $scope.formData object, you can see that it has two properties for phone and type, so the way you were checking for that in the if block was not correct. Here are the controller changes:
.controller('formController', function($scope, $location) {
// we will store all of our form data in this object
$scope.formData = {};
// function to process the form
$scope.processForm = function() {
if ($scope.formData.phone == 'iphone' && $scope.formData.type == 'xbox'){
$location.path('/results');
}
};
});
Next, routes had to be configured for the results route. Just needed to add this in your route configuration:
.state('results', {
url: '/results',
templateUrl: 'results.html'
});
Here is a forked Plunker: http://plnkr.co/edit/GUpNMRPU0YqfOcveB0nP?p=preview
I'm working on a MEAN app that is based upon Brian Ford's angular-express-blog app on GitHub.
The problem I'm having is that I need to be able to call my UserService service on $locationChangeStart in order to check if there is a user logged. Most of the examples I see have you setting $rootScope.$on('$locationChangeStart'... in the module declaration. This doesn't allow me to access my custom service so my solution was to put it in a controller and call it in my main layout file.
I've set it up like so but the app does nothing. It doesn't even call an error. Can any of you spot the problem with this code?
Here is my github repo.
LayoutCtrl.js:
angular.module('myApp').
controller('LayoutCtrl', function($scope, $http, UserService) {
$scope.$on( "$locationChangeStart", function(event, next, current) {
if ( UserService.getUser() === null ) {
// no logged user, we should be going to #login
if ( next.templateUrl == "partials/login.html" ) {
// already going to #login, no redirect needed
} else {
// not going to #login, we should redirect now
$location.path( "/login" );
}
}
});
});
Layout.jade:
doctype html
html(ng-app="myApp", ng-controller='LayoutCtrl')
head
meta(charset='utf8')
base(href='/')
title Angular Express Seed App
link(rel='stylesheet', href='/css/app.css')
body
block body
And UserService.js:
angular.module('myApp').
service('UserService', function(){
var $scope = this;
var user = null;
$scope.user = {};
$scope.setUser = function(data){
user = data;
};
$scope.getUser = function(){
$scope.user = user;
};
return $scope;
});
I don't understand how your service is supposed to work, your getUser function returns nothing (undefined).
Use this instead:
angular.module('myApp').
service('UserService', function(){
var user;
this.setUser = function(data){
user = data;
};
this.getUser = function(){
return user;
};
});
so your problem is that undefiend !== null
and you are checking for this:
if ( UserService.getUser() === null )
if you want to check if it's undefined (or other falsy values) use this:
if ( ! UserService.getUser() )
also you should inject $location:
controller('LayoutCtrl', function($scope, UserService, $location) {
Debugging
use console.log to check the flow of your application
console.log(UserService.getUser()) # undefined
alternative solution with a run block :
angular.module('myApp').
run(function($rootScope, UserService, $location) {
$rootScope.$on( "$locationChangeStart", function(event, next, current) {
});
});