Best way to integrate captcha in angularJS - javascript

I'm relatively new to angularJS and I wonder what would be the cleanest solution to the following problem.
Let's say I have a form such as follows
<form name="contactform">
<select id="salutation" name="salutation" required="true" ng-model="contactRequest.salutation"><option value="Herr" selected="">Herr</option><option value="Frau">Frau</option></select>
<img width="255" height="70" alt="" src="/website/var/tmp/aed4d639a26c4614cdac2a967381c61c.png" name="captcha[img]">
<captcha-reloader reload-url="/refresh-captcha" img-tag-name="captcha[img]" hidden-field-name="captcha[id]"></captcha-reloader>
<input type="text" name="captcha[input]" required="true" ng-model="contactRequest.captcha.input">
<input type="text" style="display: none;" ng-model="contactRequest.captcha.id" value="aed4d639a26c4614cdac2a967381c61c" name="captcha[id]">
...
As you can see, it uses a directive to display a button which will reload the CAPTCHA. It is defined as
myApp.directive('captchaReloader', function () {
return {
restrict: 'E',
scope: {
reloadUrl: '#',
imgTagName: '#',
hiddenFieldName: '#'
}, //isolate scope
template: '',
link: function (scope, element, attrs) {
},
controller: function ($scope, $element, $attrs, $http) {
$scope.reloadCaptcha = function () {
$http.get($attrs.reloadUrl).then(function (res) {
angular.element('img[name="' + $attrs.imgTagName + '"]').attr('src', res.data.imgSrc);
angular.element('input[name="' + $attrs.hiddenFieldName + '"]').val(res.data.id);
angular.element('input[name="' + $attrs.hiddenFieldName + '"]').trigger('input');
});
};
}
};
)};
If I click on the button, the captcha image and value (hidden field) are updated. It works fine so far.
Now, I want to handle form submission in controller (see methode below). If there is an error (server-side validation), the captcha has to be updated. I don't know whats the best way to trigger the updated-process defined in the directive. Can anyone help?
myApp.controller('KontaktCtrl', function ($scope, $location, CustomerDataService, CaptchaService) {
$scope.contactRequest = {
salutation: 'Herr',
captcha: {
id: initialCaptchaId
}
};
$scope.errors = {};
$scope.submitAction = function () {
CustomerDataService.sendRequest($scope.contactRequest).then(function (res) {
var data = res.data;
if (res.data.data !== null) { //errors in form. Display them
//error handling
$scope.reloadCaptcha();
} else {
goToHomeView();
}
}, function (error) {
console.log('An error occurred while updating!', error);
});
};
var goToHomeView = function () {
$location.path('/');
};
});
Additionally, I have to init the values of select-box and captcha, cause otherwise they are not sent (because the are untouched). Is there any way to avoid this?
PS: I found a reCAPTCHA directive, but reCAPTCHA is no option due to styling limitations.

Its very simple follow the steps...
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit"
async defer></script>
<script>
var onloadCallback = function() {
widgetId1 = grecaptcha.render('example1', {
'sitekey' : 'Site-Key-',
'theme' : 'light'
});
};
</script>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit"
async defer>
Now at the form put it
<div id="example1"></div>
<p style="color:red;">{{ captcha_status }}</p>
Validate with angular
if(grecaptcha.getResponse(widgetId1)==''){
$scope.captcha_status='Please verify captha.';
return;
}

Related

Angular typeahead asynchronous results - receiving error "TypeError: Cannot use 'in' operator to search for ... in ..."

I have made a directive for an Angular UI typeahead field. I am trying to design it so that as a user is typing, it sends asynchronous backend calls for results that will populate the dropdown that appears, as demonstrated in the Angular-bootstrap docs, example 2. However, when I start typing ('a' in this case), I get the error:
TypeError: Cannot use 'in' operator to search for 'getters' in a
Here is the factory method that makes the REST call:
certFactory.getUsersWithMatchingUsername = function(username) {
return $http.get(urlBase + '/managed/user?_queryFilter=userName+co+' + '\'' + username + '\'', {timeout: timeoutLength})
.then(function(response) {
// success
return response.data;
}, function(response) {
// error
return $q.reject(response);
});
};
Here is the controller method that calls the factory method:
$scope.getters = {
getUsersWithUsername: function (username) {
certFactory.getUsersWithMatchingUsername(username)
.then(function (response) {
var users = [];
angular.forEach(response.result, function(item) {
users.push(item);
})
return users;
}, function (error) {
console.log('failed!')
})
}
Here is my directive:
angular.module('myApp')
.directive('dropdownsearch', function(){
return {
restrict: 'E',
transclude: true,
scope: {
getterFn: '&',
config: '=', // object with properties label and type
disabled: '=?ngDisabled',
required: '=?ngRequred',
ngModel: '=',
options: '='
},
require: ['^form', 'ngModel'],
templateUrl: 'views/templates/dropdownSearchView.html',
replace: true,
link: function(scope, iElm, iAttrs, controller) {
if (iAttrs.required !== undefined) {
// If attribute required exists
// ng-required takes a boolean
scope.required = true;
}
if (iAttrs.readonly !== undefined) {
// If attribute required exists
// ng-required takes a boolean
scope.readonly = true;
}
}
}
}
);
Here is the directive template:
<div class="form-group has-feedback">
<label class="control-label"> Choose {{ config.type }}></label>
<div class="dropdown dropdown">
<div class="input-group">
<input
type="text"
class="form-control"
placeholder="Make selection"
ng-model="ngModel"
uib-typeahead="option as option[config.label] for option in getterFn($viewValue)"
typeahead-editable="false"
ng-required="required"
ng-disabled="disabled"
/>
</div>
</div>
</div>
And finally, here is my directive in use:
<dropdownsearch ng-show= 'fieldMethods.showSubfield(subfield)'
getter-fn="getters.getUsersWithUsername"
ng-model="subsubfield.value"
config="fieldMethods.getConfig(subfield)">
</dropdownsearch>
Any help would be greatly appreciated. Also, let me know if any additional info is required.
The UI Bootstrap website Asynchronous Typeahead example uses uib-typeahead="address for address in getLocation($viewValue)". My guess is that your error message is saying that it's expecting for, not as in the directive. I don't understand this so I could be wrong! :-)

ng-show - using a service as a scope parameter

I'm writing an angular 1.5.0-rc0 application using bootstrap for a nav bar component.
I want to show the user an added items to his navigation bar if his user group id is 1.
first I created a service:
app.factory('UserService', function() {
return {
userGroupId : null
};
});
I created the nav bar as a directive, so i included it in the main html file
<nav-bar></nav-bar>
and the nav-bar directive code:
(function () {
angular.module('myalcoholist').directive('navBar', function () {
return {
restrict: 'E',
templateUrl: 'views/nav.html',
controller: ['$scope','$auth', 'UserService',function ($scope,$auth,UserService) {
$scope.user=UserService;
$scope.isAuthenticated = function()
{
return $auth.isAuthenticated();
};
}]
}
});
})();
as you can see I set $scope.user as the returned object from UserService.
in my login controller, after a successful login I set the userGroupId.
angular.module('myalcoholist').controller('LoginController',['$scope','$auth','$location', 'toastr','UserService',function ($scope,$auth,$location,toastr,UserService) {
$scope.authenticate = function (provider) {
$auth.authenticate(provider).then(function (data) {
var accessToken = data.data.token;
apiKey=accessToken;
UserService.userGroupId=data.data.user_group_id;
...
now.. my nav-bar template file is as the following code:
<li ng-show="user.userGroupId == 1">
Admin Drinks
</li>
even after the authentication, when I uset userGroupId to 1 the element is still not shown.
any ideas?
update
I debugged and noticed that UserService.userGroupId is still null. so
I changed the UserService to have the following code:
app.factory('UserService', function() {
var user = {userGroupId:null};
return {
setUserGroupId: function (userGroupId) {
user.userGroupId=setUserGroupId;
},
getUserGroupId: function () {
return user.userGroupId;
}
};
});
in my LoginController I now try to execute setUserGroupId:
angular.module('myalcoholist').controller('LoginController',['$scope','$auth','$location', 'toastr','UserService',function ($scope,$auth,$location,toastr,UserService) {
$scope.authenticate = function (provider) {
$auth.authenticate(provider).then(function (data) {
var accessToken = data.data.token;
apiKey=accessToken;
UserService.setUserGroupId(data.data.user_group_id);
...
when I debug i see that userService is an object with two functions as I defined, but when the javascript chrome debugger tries to execute this line:
UserService.setUserGroupId(data.data.user_group_id);
I get the following error:
ReferenceError: setUserGroupId is not defined
at Object.setUserGroupId (app.js:21)
at login-controller.js:12
at angular.js:15287
at m.$eval (angular.js:16554)
at m.$digest (angular.js:16372)
at m.$apply (angular.js:16662)
at g (angular.js:11033)
at t (angular.js:11231)
at XMLHttpRequest.v.onload (angular.js:11172)
I have created a fiddle showcasing your requirement (as close as possible), and it seems to work fine.
http://jsfiddle.net/HB7LU/21493/
My guess is that you aren't actually setting the value when you think you are, and will likely require some debugging. Here is the code for brevity.
HTML
<div ng-controller="MyCtrl">
<div ng-click="clicked()">
Click ME, {{user.value}}!
</div>
<test-dir></test-dir>
</div>
JS
angular.module('myApp',[])
.service('TestService', function(){
return {
value: 2
};
})
.directive('testDir', function(){
return {
restrict: 'E',
template: '<div ng-show="user.value === 1">Here is some text</div><div>Some more always showing</div>',
controller: function ($scope, TestService) {
$scope.user = TestService;
}
};
})
.controller('MyCtrl', function($scope, TestService){
$scope.user = TestService;
$scope.clicked = function(){
TestService.value = 1;
};
});

Call 2 functions in single ng-click

I am calling two functions on ng-click. But it doesn't work. I am not sure why the Refresh1() is not called when I cross-checked through debugger.
HTML CODE
<div class="row" ng-controller="PublishManifestCtrl">
<div class="col-xs-12 col-md-12">
<div class="widget">
<div class="widget-header bordered-bottom bordered-themeprimary">
<i class="widget-icon fa fa-tasks themeprimary"></i>
<span class="widget-caption themeprimary">Manifest Status</span>
</div>
<div class="widget-body">
<form class="form-bordered" role="form">
<div class="form-group">
<label style="padding-left: 8px;">Manifest was last published to agents on <b>{{manifeststatus.manifestLastPublishedDate}}</b>.</label>
</div>
<div class="form-group">
<label style="padding-left: 8px;">Manifest was last updated by <b> {{manifeststatus.lastUpdatedByUser}} </b> on <b>{{manifeststatus.manifestLastedUpdatedDate}}</b>.</label>
</div>
<div class="form-group">
<div class="col-sm-offset-1">
**<button id="PublishButton" class="btn btn-default shiny " ng-disabled="manifeststatus.enablePublishButton" ng-click="Save(manifeststatus);Refresh1()">Publish</button>**
</div>
<br/>
<div id="statusDivPublish" ng-show="showstatus">
<alert type="{{alert.type}}">{{alert.msg}}</alert>
</div>
</div>
</form>
</div>
JSFILE
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
}
$scope.Refresh1 = function () {
//refresh
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
}
});
new code
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.Refresh1();
}
$scope.Refresh1 = function ($rootScope, $state, $stateParams) {
debugger;
return {
restrict: 'AC',
link: function (scope, el, attr) {
el.on('click', function () {
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
});
}
};
};
});
The first one updates and displays a successfull message, while the second function refreshes the page.
use this
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.refresh();
}
call refresh inside the first function and remove it from the ng-click.
Update
You have a different type of problem i had it too. you try to refresh a state inside a method, it's really difficult i solve that problem with this snippet
if($state.current.name == /*name of the current state*/) {
$state.go($state.current, {}, {reload: true});
$modalInstance.close();
}
else {
$modalInstance.close();
$state.go(/*name of the current state*/);
}
it's not difficult but it didn't behave like you have understand it.
UPDATE
taking your code
$scope.Refresh1 = function () {
//refresh
$state.go($state.current, {}, {reload: true});
}
What about calling refresh inside of save in $http handler ?
Like this:
$http.post($rootScope.WebApiURL + '/updatemanifeststatus')
.then(function(){
$scope.Refresh1();
});
Don't execute two function in one ng-click, instead add the Refresh1 call to the end of the Save call, like so.
HTML
<button id="PublishButton"
class="btn btn-default shiny "
ng-disabled="manifeststatus.enablePublishButton"
ng-click="Save(manifeststatus)">Publish</button>
JS
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.refresh();
}
Update
If you are using AngularJS V1.2.2 or higher, then using ui-router, the following should work to reload the data.
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
The shortest way to accomplish this though would be with:
$state.go($state.current, {}, {reload: true}); //second parameter is for $stateParams
Its also worth noting that none of these will actually reload the page. If you want to reload the state AND the page, there is no ui-routermethod for it. Do window.location.reload(true)
Update 2
If you are receiving:
$state is not defined at Scope.$scope.Refresh1
(publishmanifest.js:44) at Scope.$scope.Save (publishmanifest.js:37)
at $parseFunctionCall (angular.js:12345) at angular-touch.js:472 at
Scope.$eval (angular.js:14401) at Scope.$apply (angular.js:14500) at
HTMLButtonElement. (angular-touch.js:471) at
HTMLButtonElement.n.event.dispatch (jquery.min.js:3) at
HTMLButtonElement.r.handle (jquery.min.js:3)
You are not injecting the $state service in your controller. You must do this in order to use it.
//without annotation (inferred, not safe when minifying code)
function Controller($scope, $state) {...}
//inline annotation
module.controller('Controller', ['$scope','$state', function($scope, $state) {...}]);
//$inject property annotation
function Controller($scope, $state) {...}
Controller.$inject = ['$scope', '$state'];
Pick one of the methods above to setup your controller to use $state.
Just make a third function like:
function3(data) {
save(data);
refresh1();
}

Angular Directive Element dynamic Template fields with its updated model value from controller?

I have <superhero> directive which has two directive
web-buttons to take of the form validation and post the updated
ngModel value to respective controller
fieldMap directive to generate the dynamic fields by object we are passing from respective controller
Here is the example which i have worked
directive attribute called saveFormFn will tell the button to call which function to invoked using enter attribute directive.
For example. After click save button it will call the function 'Ctrl1saveFormFn' from controller Ctrl1 .This function will make ajax post to save the form fields.
After updating the text fields with some content and click save,I have passed the current scope of the directive to respective controller (see console log). i could not get the updated fielddata value from current Scope.
$scope.Ctrl1saveFormFn = function(item){
_.each(item,function(currentScope){
console.log(currentScope)
// here i want to collect the form data with updated fielddata values
})
}
I am beginner.Am i on right path? Please advice
I've re-written your code because it was pretty hard to understand.
I would do it like this:
Use ng-include to load the template of your buttons. That's loading the control buttons edit and save.
Save your data in a variable in the superhero directive. Maybe it would be even better to store it in a separate service/factory.
Create a directive customForm that will create a form based on the supplied model that you're passing to its scope.
The main application logic is in the superhero directive because it is adding the controls save/edit to the DOM. If saving/editing is not only related to the superhero it would be better to do it in your main controller.
Please have a look at the demo below or in this jsfiddle.
angular.module('demoApp', [])
.directive('superhero', Superhero)
.directive('customForm', CustomForm)
.controller('mainController', MainController);
function Superhero() {
return {
restrict: 'E',
scope: {
formModel: "=",
},
template: '<div class="hero"><div ng-include="\'web-buttons.html\'"></div><custom-form model="formModel"></custom-form></div>',
controllerAs: 'superHeroCtrl',
controller: function ($scope) {
var self = this;
console.log('controller directive');
angular.extend(this, {
abilities: [],
editMode: false,
addStrength: function (data) {
self.abilities.push(data);
},
getStrength: function () {
return self.abilities;
},
showSave: function() {
self.editMode = true;
$scope.formModel.editMode = true;
},
hideSave: function() {
self.editMode = false;
$scope.formModel.editMode = false;
},
save: function() {
self.addStrength('can fly');
console.log(self.getStrength());
console.log('saving data now of form now...', $scope.formModel.data);
alert('saving data of form now: ' + self.getStrength()[0] + ' - ' + JSON.stringify( $scope.formModel.data, null, 2));
self.hideSave();
}
});
}
}
}
function CustomForm() {
return {
restrict: 'EA',
scope: {
model: '='
},
template: '<div ng-if="model.editMode" ng-repeat="formElement in model.fields" ng-include="formElement.template.url"></div>'
}
}
function MainController() {
this.normalForm = {
editMode: false,
data: {
},
fields: {
'NAME':{
template: {
url: 'customForms/text.html',
type: 'edit' // not sure for what it is needed
},
label: 'First name',
id: "NAME",
placeholder : "First Name",
fieldData: "NAME",
key : 'first_name'
},
'LNAME': {
template: {
url: 'customForms/text.html',
type: 'edit' // not sure for what it is needed
},
label: "Last Name",
placeholder : "Last Name",
id: "LNAME",
key : 'last_name'
}
}
};
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="mainController as mainCtrl">
<script type="text/ng-template" id="customForms/text.html">
<label for="{{formElement.id}}">{{formElement.label}}</label>
<input ng-model="model.data[formElement.key]" placeholder="{{formElement.placeholder}}" id="formElement.id"/>
</script>
<script type="text/ng-template" id="web-buttons.html">
<button ng-click="superHeroCtrl.showSave()" ng-if="!superHeroCtrl.editMode">edit</button>
<button ng-if="superHeroCtrl.editMode" ng-click="superHeroCtrl.save()">save</button>
</script>
<superhero form-model="mainCtrl.normalForm"></superhero>
<h3>debug output:</h3>
<pre>
{{mainCtrl.normalForm |json}}
</pre>
</div>

Angular ui grid how to show a loader

I'm wondering how to show a simple loader before data was loaded.
I'm using ng-grid-1.3.2
I'm googling but I didn't find any example.
Bye
like Maxim Shoustin suggested you can use the angularjs-spinner from Jim Lavin which uses (deprecated) Response Interceptors.
I think it's explained best here :
http://codingsmackdown.tv/blog/2013/04/20/using-response-interceptors-to-show-and-hide-a-loading-widget-redux/
In a nutshell, in his first solution, what you have to do for your ng-grid app is:
1) Add the loading gif to your html (for loading gif look here)
<div id="loadingWidget" class="row-fluid ui-corner-all" style="padding: 0 .7em;" loading-widget >
<div class="loadingContent">
<p>
<img alt="Loading Content" src="images/ajax-loader.gif" /> Loading
</p>
</div>
</div>
2) In your code as soon as you have declared your app level module add the Response Interceptors for http requests to the configuration block
var app = angular.module('myCoolGridApp', ['ngGrid']);
app.constant('_START_REQUEST_', '_START_REQUEST_');
app.constant('_END_REQUEST_', '_END_REQUEST_');
app.config(['$httpProvider', '_START_REQUEST_', '_END_REQUEST_', function ($httpProvider, _START_REQUEST_, _END_REQUEST_) {
var $http,
interceptor = /* see extra details on codingsmackdown.tv */
$httpProvider.responseInterceptors.push(interceptor);
}
3) and then add your loadingWidget directive
app.directive('loadingWidget', ['_START_REQUEST_', '_END_REQUEST_', function (_START_REQUEST_, _END_REQUEST_) {
return {
restrict: "A",
link: function (scope, element) {
element.hide();
scope.$on(_START_REQUEST_, function () {element.show();});
scope.$on(_END_REQUEST_, function () {element.hide();});
}
};
}]);
See more details at codingsmackdown
I had the same question as you.
I find this nice tutorial about it: http://brianhann.com/ui-grid-the-easiest-customization-youll-ever-write/
He use vm.loading = true while fetching data from server and changed to false after complete.
var app = angular.module('app', ['ngTouch', 'ui.grid']);
app.controller('MainCtrl', ['$http', '$timeout', function ($http, $timeout) {
var vm = this;
vm.reset = reset;
vm.noData = noData;
vm.gridOptions = {
columnDefs: [
{ field: 'name' },
{ field: 'age' }
]
};
reset();
////////////
// Initialize our data source
function init() {
$http.get('data.json')
.success(function (data) {
vm.gridOptions.data = data;
})
.finally(function () {
vm.loading = false;
});
}
// Reset the data source in a timeout so we can see the loading message
function reset() {
vm.loading = true;
vm.gridOptions.data = [];
$timeout(function () {
init();
}, 1000);
}
function noData() {
vm.gridOptions.data = [];
}
}]);
In the HTML, he uses ng-hide to show/hide the spinner based on values of gridOptions.data and vm.loading:
<div id="grid1" ui-grid="vm.gridOptions" class="grid">
<div class="grid-msg-overlay" ng-hide="!vm.loading">
<div class="msg">
<span>
Loading Data...
<i class="fa fa-spinner fa-spin"></i>
</span>
</div>
</div>
<div class="grid-msg-overlay" ng-hide="vm.loading || vm.gridOptions.data.length">
<div class="msg">
<span>No Data</span>
</div>
</div>
</div>
Here is the Plunker of the final version shown.
You have angularjs-spinner, see GitHub sources
I also needed a similar behavior and I came across this answer but I needed to show something inside the grid itself so here is something I put together. My idea is that I change the gridOptions on the fly and show a loader as a row inside the grid.
loaderOptions = {
"columnDefs": [{
"name": "",
"field": "loading",
"enableColumnMenu": false,
"cellTemplate": '<div style="width:90px; margin:auto;"><span class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></span> Loading...</div>'
}],
"data": [{
"loading": ""
}]
};
Simply,by adding this code in your html part:
<img alt="loading..." src='images/ajax-loader.gif")' /> loading message...
and the following code in your app.controller script:
$http.get(yourdataUrl)
.then(function (response) {
$scope.records = response.data;
$("#loadingWidget").hide();
});
it works fine for me!
The HTML code-sample
<img ng-show="loading" src="~/img/loding.jpg" />
<div class="ngtyle" ng-grid="myGridView"></div>
The AngularJs code-sample
var app = angular.module('App', ['ngGrid']);
app.controller('MainCtrl', function ( $scope, myService ) {
$scope.loading = true;
myService.get().then( function ( response ) {
$scope.items = response.data;
})
.finally(function() {
$scope.loading = false;
});
$scope.myGridView = {
data: 'dataList',
columnDefs: 'myDisplayColumns'};
});

Categories