Passing angular 1 controller scope method as callback to captcha library - javascript

I have a client who is based in china and requires specialised captcha that works there. The captcha I need to use is here https://open.captcha.qq.com/
Basically there are 4 steps to get it working:
In the label of html, add this line:
<script src="https://ssl.captcha.qq.com/TCaptcha.js"></script>
Add id and property to any DOM element that we want to activate captcha, such as button, div or span. Sample code as below:
<button id="TencentCaptcha"
data-appid="2090807227"
data-cbfn="callback"
>验证</button>
Then create callback function in javascript:
function callback(res){
console.log(res)
if(res.ret == 0){
alert(res.ticket) // ticket
}
}
From the callback, make a POST request to the server to validate the ticket
I'm struggling this to incorporate this into my UI which uses Angular 1.5.6.
My controller is:
.controller('MyCtrl', function($scope) {
$scope.oldCallback = function(){
console.log('in the old callback');
};
$scope.newCallback = function(){
// PASS THIS AS THE CALLBACK TO NEW REGISTER BUTTON
};
})
I have created a CodePen here.
The only way I can get it remotely working is if I pass in a method in the HTML e.g.
<button type="submit" id="TencentCaptcha"
data-appid="2090807227"
data-cbfn="(function(res){alert('res is ' + res)})">
Register
</button>
After clicking Register, the captcha library presents a popup with a challenge to the user. Once completed, the callback passed to data-cbfn is executed. How can I call my controller method from this callback, passing through the result?

I created a global function and was then able to call the correct method in the controller:
function callback(){
var scope = angular.element(document.getElementById("home")).scope();
scope.register();
}

You could also add your function to the window from your angular controller:
.controller('MyCtrl', function($scope, $window) {
$window.callback = function callback(res) {
$scope.register();
};
});
This way you don't have to request the document element which may change scope or id later on.
Also: $compileProvider.debugInfoEnabled(false); will actually disable the functionality to retrieve the scope from a document element like you've done.
You should be turning off the debugInfo functionality in production mode for performance and security reasons.

Related

transfer of information from one function to another through a global variable in angular controler

I have a little trouble with passing value from one function to another in one angular controller.
i have event
onTimeRangeSelected: function (args) {
$scope.dayPilotCal.clearSelection();
$scope.createNewEventModalWindow(args);
},
event call function
$scope.createNewEventModalWindow = function(args)
{
console.log('create new event dialog');
$rootScope.newEvent.start = args.start.value;
console.log($rootScope.newEvent.start);
ngDialog.open({
......
});
}
than i handle dialog confirm button click event
<button
type="button"
class="ngdialog-button ngdialog-button-primary"
ng-click="btnCreateEventClicked()"
>Create</button>
and call function
$scope.btnCreateEventClicked = function(){
console.log('btn create event clicked');
ngDialog.close();
console.log($rootScope.newEvent.start);
};
so that my problem - in first case console.log($rootScope.newEvent.start); print to console real date. But in the second function console.log($rootScope.newEvent.start); print into console 'undefined' value.
all code are in the same controller. And in the first lines of controller i define my global variable $rootScope.newEvent={};
Please help me in that problem.
Global variables makes testing the code really difficult. Because any function can have access to the global scope. In your example I would assume their is another part of your coding that changes $rootScope.newEvent.
If this variable has to be globally available I would suggest to use a service.
If their is no need for this var to be globally accessible, than just change $rootScope.newEvent to $scope.newEvent.

Integrating non-Angular code?

I'm developing a Cordova/PhoneGap app, and I'm using the $cordovaPush plugin (wrapped for PushPlugin) to handle push notifications.
The code looks something like this:
var androidConfig = {
"senderID" : "mysenderID",
"ecb" : "onNotification"
}
$cordovaPush.register(androidConfig).then(function(result) {
console.log('Cordova Push Reg Success');
console.log(result);
}, function(error) {
console.log('Cordova push reg error');
console.log(error);
});
The "ecb" function must be defined with window scope, ie:
window.onNotification = function onNotification(e)...
This function handles incoming events. I'd obviously like to handle incoming events in my angular code - how can I integrate the two so that my onNotification function can access my scope/rootScope variables?
Usually, you'll wrap your 3rd party library in a service or a factory, but in the spirit of answering your particular scenario...
Here's one possibility:
angular.module('myApp').
controller('myController', function($scope, $window) {
$window.onNotification = function() {
$scope.apply(function() {
$scope.myVar = ...updates...
});
};
});
A couple of things to notice:
Try to use $window, not window. It's a good habit to get into as it will help you with testability down the line. Because of the internals of Cordova, you might actually need to use window, but I doubt it.
The function that does all of the work is buried inside of $scope.apply. If you forget to do this, then any variables you update will not be reflected in the view until the digest cycle runs again (if ever).
Although I put my example in a controller, you might put yours inside of a handler. If its an angular handler (ng-click, for example), you might think that because the ng-click has an implicit $apply wrapping the callback, your onNotification function is not called at that time, so you still need to do the $apply, as above.
...seriously... don't forget the apply. :-) When I'm debugging people's code, it's the number one reason why external libraries are not working. We all get bit at least once by this.
Define a kind of a mail controller in body and inside that controller use the $window service.
HTML:
<body ng-controller="MainController">
<!-- other markup .-->
</body>
JS:
yourApp.controller("BaseController", ["$scope", "$window", function($scope, $window) {
$window.onNotification = function(e) {
// Use $scope or any Angular stuff
}
}]);

How to reload an angular controller with the updated $scope?

My problem is I need "det" value applied to the controller and reload it.
Anyway nevermind it and continue reading first so you will understand my question.
I have this controller below.
At first load, the xxx isn't going to exist in the object then det value will be null. So it is expected that the controller's service will have an error telling that it can't be find. (See Controller code below)
However, when I click a button on my page (buttons html code is not here, I don't think it is necessary), it fills the object in and I'm wishing to reload the controller so I will see my expected output.
The HTML below is the one who loads the controller, what I'm expecting is that the
data-ng-model="{{$parent.$root.ParentItems['xxx'].xxx}}" will update the xxx value in controller. And it actually does because I'm using "<span>{{$parent.$root.ParentItems['xxx'].detnumber}}</span>" to test it.
Now, again,
My problem is I need the "det" value applied to the controller and reload it.
What I'm thinking is to create a new controller but I will just repeat the code.
//html
<div data-ng-switch-when="thisIsIt" ControllerOne data-ng-model="{{$parent.$root.ParentItems['xxx'].xxx}}"></div>
<span>{{$parent.$root.ParentItems['xxx'].xxx}}</span>
//Attribute ControllerOne
controller: function ($scope, $element, $http) {
function par() {
var xxx= null;
xxx = $scope.$parent.$root.ParentItems['xxx'].xxx;
var det = { xxx: xxx};
return det;
}
$http.post('/api/values/entries/GoHere', par()).success(function (salData) {
var buildSHGraph = function (shData) {
//code code codes...
}
$scope.Array1 = [];
angular.forEach(salData, function (evt) {
//Code Code Codes
});
buildSHGraph($scope.Array1);
});
}
I thing you can use $rootScope and pass your value to it. Then the value can be accessible globally by your application.
When your value is downloaded from ajax, the scope/html will be updated.
When you define variable with 'var xxx' cannot access it outside of the scope of this function, in your case 'par'.
function par() {
this.xxx = null;
this.xxx = $scope.$parent.$root.ParentItems['xxx'].xxx;
}
When you try to change view from callback from async task such as $http.post you need to '$digest' or '$apply' the scope
//Do this in success callback function in your ajax request
$timeout(function() { //$timeout must be setup as dependency in constructor such as $scope and $http
$scope.$digest();
});

AngularJS: Custom $anchorScroll provider execution

I need to scroll to a specific anchor tag on page reload. I tried using $anchorScroll but it evaluates $location.hash(), which is not what I needed.
I wrote a custom provider based on the source code of $anchorScrollProvider. In it, it adds a value to the rootScope's $watch list, and calls an $evalAsync on change.
Provider:
zlc.provider('scroll', function() {
this.$get = ['$window', '$rootScope', function($window, $rootScope) {
var document = $window.document;
var elm;
function scroll() {
elm = document.getElementById($rootScope.trendHistory.id);
if (elm) elm.scrollIntoView();
}
$rootScope.$watch(function scrollWatch() {return $rootScope.trendHistory.id;},
function scrollWatchAction() {
if ($rootScope.trendHistory.id) $rootScope.$eval(scroll);
});
return scroll;
}];
});
Now, when I try to call the scroll provider in my controller, I must force a digest with $scope.$apply() before the call to scroll():
Controller:
//inside function called on reload
$scope.apply();
scroll();
Why must I call $scope.$apply()? Why isn't the scroll function evaluating in the Angular context when called inside the current scope? Thank you for your help!
I'm not sure what your thinking is behind using $rootScope.$eval(scroll) - since the scroll() function is already executing in a context where it has direct access to the $rootScope.
If I understand correctly, you want to be able to scroll to a particular element as denoted by an id which is stored in $rootScope.trendHistory.id.
When that id is changed, you want to scroll to that element (if it exists on the page).
Assuming this is a correct interpretation of what you are trying to achieve, here is how I might go about implementing it:
app.service('scrollService', function($rootScope) {
$rootScope.trendHistory = {};
$rootScope.$watch('trendHistory.id', function(val) {
if (val) {
elm = document.getElementById($rootScope.trendHistory.id);
if (elm) elm.scrollIntoView();
}
});
this.scrollTo = function(linkId) {
$rootScope.trendHistory.id = linkId;
}
});
This is a service (like your provider, but using the simpler "service" approach) which will set up a $watch on the $rootScope, looking for changes to $rootScope.trendHistory.id. When a change is detected, it scrolls to the element indicated if it exists - that bit is taken directly from your code.
So to use this in a controller, you'd inject the scrollService and then call its scrollTo() method with the ID as an argument. Example:
app.controller('AppController', function($scope, scrollService) {
scrollService.scrollTo('some_id');
});
In your question, you mention this needing to occur on reload, so you'd just put the call into your reload handler. You could also just directly modify the value of $rootScope.trendHistory.id from anywhere in the app and it would also attempt to scroll.
Here is a demo illustrating the basic approach: http://plnkr.co/edit/cJpHoSemj2Z9muCQVKmj?p=preview
Hope that helps, and apologies if I misunderstood your requirements.

AngularJS controller and methods

I'm a beginner in angularjs with a few questions about controllers.
Here's my example controller:
function exampleController($scope)
{
$scope.sampleArray = new Array();
$scope.firstMethod = function()
{
//initialize the sampleArray
};
$scope.secondMethod = function()
{
this.firstMethod();
};
};
Here are my questions:
How I can call firstMethod from secondMethod? Is the way I did it correct, or is better way?
How I can create a constructor for the controller? I need to call the secondMethod that call the firstMethod that initialize the sampleArray?
How I can call a specific method from html code? I found ng-initialize but I can't figure out how to use it.
You call a method the same way you declared it:
$scope.secondMethod = function() {
$scope.firstMethod();
};
Which you can also call from HTML like so:
<span>{{secondMethod()}}</span>
But controllers don't really have "constructors" - they're typically used just like functions. But you can place initialization in your controller function and it will be executed initially, like a constructor:
function exampleController($scope) {
$scope.firstMethod = function() {
//initialize the sampleArray
};
$scope.secondMethod = function() {
$scope.firstMethod();
};
$scope.firstMethod();
}
you call the first method by using $scope.
So
$scope.secondMethod = function()
{
$scope.firstMethod();
};
Not really sure what you mean in your second question.
For your third quesiton, you can either have the method run automatically "onload" on controller, OR run it via an front-end angular binding.
e.g.
Run Automatically
function exampleController($scope)
{
$scope.sampleArray = new Array();
$scope.firstMethod = function()
{
//initialize the sampleArray
};
$scope.secondMethod = function()
{
$scope.firstMethod();
};
$scope.secondMethod(); // runs automatically.
};
Run on binding
<div ng-controller="ExampleController"> <!-- example controller set up in namespace -->
<button class="btn" ng-click="secondMethod()">Run Second Method</button>
</div>
#Josh and #Christopher already covered your questions, so I won't repeat that.
I found ng-initialize but I can't know how to use that :-(
The directive is actually ng-init. Sometimes (e.g., if you are starting to use Angular in parts of an application and you still need to dynamically generate a view/HTML page server-side), ng-init can sometimes a useful way to initialize something. E.g.,
<div ng-controller="ExampleCtrl">
<form name="myForm">
<input type="text" ng-model="folder" ng-init="folder='Bob'">
Here's an example where someone needed to use ng-init: rails + angularjs loading values into textfields on edit
I'd also like to mention that controllers are not singletons. If you use ng-view, each time you go to a different route, a new controller is created. The controller associated with the view you are leaving is destroyed, and the controller associated with the view you are going to is executed. So that "initialization code" in a controller could get executed multiple times while an app is running. E.g, if you visit a page, go elsewhere, then come back, the same controller function (and its "initialization code") would be executed twice.
If you want something to truly run once, put it in a service or in a module's config() or run() methods. (Services are singletons, and hence each service is instantiated only once, so initialization code in a service is only run once.)

Categories

Resources