I am learning angularjs and a bit confused. I am creating an angular module and controller functions like this:
var mapApp = angular.module("mapApp", []);
mapApp.controller("mapController", function($scope) {
$scope.save = function() {
//do domething
};
});
And I have other functions out of the controller.
function onMapClickEvent(e) {
//do domething
}
When map clilcked, I want to populate angular save function. Is this possible.
I asked this because sometimes we need to work with more then one API. AngularJS and Google Maps API. One API function need to populate other API.
You can cast DOM element to Angular element in this way:
angular.element(DOM)
And get the current scope of DOM by invoking scope()
angular.element(DOM).scope()
Then you can access any member of this scope, in your example: save()
I implemented a simple example, you could try it:
HTML
<div ng-controller="myCtrl">
<button id="testBtn" onclick="onClick(this)">test</button>
</div>
JS
angular.module("app",[])
.controller("myCtrl",function($scope){
$scope.angularWorldFunction = function(){
console.log("message from angular world");
}
});
function onClick(target){
angular.element(target).scope().angularWorldFunction();
}
Here is jsFiddle demo
Hope this helpful.
Related
I have two js files, app.js and datepicker.js. I have nothing to do with the html file here. There is a javascript function called clickApply() in datepicker.js. I want to call another submitDetails() function which is inside the app.js file from the clickApply() function. How to do it?
angular.module('ctrl').controller('MyCtrl', ["$scope","$rootScope", function($scope, $rootScope){
$rootScope.submitDetails=function()
}]);//inside app.js
clickApply: function(e) { //inside datepicker.js
angular.element('#span').on("click",submitDetails());
this.hide();
this.element.trigger('apply.daterangepicker', this);
}
No one prefer executing the angular functions outside of angular scope. If you want to implement a jQuery or any other external plugin in AngularJS, wrap it in directive and use it.
Below code is used for debugging purpose only.
Change your clickApply function signature to below:
For accessing scope you can use angular.element(element).scope()
For rootScope you can use angular.element('body').scope().$root`
clickApply: function(e) { //inside datepicker.js
angular.element('#span').on("click", function(e) {
// if you want to access rootScope
var rootScope = angular.element('body').scope().$root;
rootScope.submitDetails();
// if you want to access current scope
// var scope = angular.element(e.target).scope();
// scope.submitDetails();
});
this.hide();
this.element.trigger('apply.daterangepicker', this);
}
$I have a custom javascript object, that can fire events.
I would like to access the angular $scope inside the event-handler, but I have read somewhere that using angular.element(...).scope() is not good, because it's only meant for testing.
My other idea was to register the handle on my object inside the controller, but this is not working (looks like $scope.somevalue gets set, but I don't think $scope is the same object).
I have found many answers here on Stack Overflow for similar questions, but they all seem to be using directives. All I want is to get a value from the object when it's updated, and display it.
Here are the two ways I have tried.
var myObj = GetMyObjInstance();
// Working, but apparently it's not good practise to call .scope() on an element.
myObj.onUpdated = function(){
console.log("myObj updated");
var v = myObj.getValue();
var controllerDiv = document.getElementById("controller");
var $scope = angular.element(controllerDiv).scope();
$scope.apply(function(){
$scope.someValue = v;
});
}
// Tried to do this, thinking i would get closure on the scope.
angular.module('myApp', []).controller('controller', function($scope){
myObj.onUpdated = function(){
console.log("myObj updated"); // Gets logged to console...
var v = myObj.getValue();
$scope.somevalue = v; // ... but somevalue does not get displayed.
$scope.apply(); // Error, says it's not a function, so maybe this is not the right object?.
}
});
Use AngularJS directives to handle events and update scope.
app.directive("xdEvent", function() {
return linkFn(scope, elem, attrs) {
elem.on("event", function(e) {
scope.$eval(attrs.xdEvent, {$event: e});
scope.$apply();
});
};
};
USAGE
<div xd-event="fn($event)"></div>
I think using a Service instead of a controller is a better practice. You can call a service from outside javascript with the injector like explained in this thread :
Call angularjs service from simple js code
If it is still important for you to access this variables from controller, you can use $watch to tell your controller to update itself when the service variables change.
Hope this help.
A+
I have research through the internet with this popular error and I have found no solution to my problem.
What I have is a jQuery iframe post message function that receive strings from a different domain. When it get the string it will need to store it to Angular and save to the database. What I am having the trouble is, trying to update angular so that recognizes the changes.
So here is my code:
.controller('jobOrderController', function(Jobs, socketio) {
var vm = this;
var myImage;
$.receiveMessage(
function(e) {
myImage = e.data;
vm.$apply(function() {
vm.orderData.guideImage = e.data
});
},
'http://aaa.com'
);
vm.createOrders = function() {
vm.message = '';
Jobs.createOrders(vm.orderData)
.success(function(data) {
vm.orderData = '';
vm.message = data.message;
});
};
})
$.receiveMessage will listen for incoming string data and then when it receive it should just save it to my "controller, vm". I know that my message is being received as I can alert them.
I know that I am going it wrong but everything I read is using $scope.apply so I thought it would work the same way using "this". But it doesn't seem to be updated to angular.
I see that you are using john papa's guideline to avoid the use of $scope.
You just forgot to declare vm (standing for viewmodel) at the beginning of your controller:
var vm = this;
EDIT: the guideline also says :
"Consider using $scope in a controller only when needed. For example
when publishing and subscribing events using $emit, $broadcast, or
$on."
For $apply as well, you need to explicitly use $scope.$apply
You can just do this:
.controller('jobOrderController', function($scope, Jobs, socketio) {
var vm = this;
$.receiveMessage(
function(e) {
myImage = e.data;
$scope.$apply(function() {
vm.orderData.guideImage = e.data
});
},
'http://aaa.com'
);
});
The this works differently inside the Angular's controller. It's not always same as the $scope and $scope is the object which contains $apply method.
For $apply, you can not use this. $scope and this are different instance so this can not access $apply.
Check snippet:
angular.module('myApp', []).controller('MyCtrl', function($scope) {
var vm = this;
setTimeout(function() {
$scope.$apply(function() {
vm.text = 'Submit';
});
}, 0);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl as ctrl">
<button>{{ctrl.text}}</button>
</div>
The controllerAs syntax is just (currently) sugar for $scope.foo (if your controllerAs is set to foo). As a result, this will actually point at $scope.foo in this instance and not $scope, which is why you will be unable to invoke any of $scope's actions through this. To use any of those, you will have to explicitly use $scope.
The above answers all answer with a solution on how to fix the short-term problem, that is, you using $scope.$apply in the controller.
Honestly, the issue here isn't that you can't use $scope.$apply - I'm not sure exactly what you are trying to do but one of the main rules of Angular is that you have to do everything through Angular; $.receiveMessage is decidedly not Angular. Wrap your $.receiveMessage into a service; that service should also handle the $scope.$apply. This will help reduce code duplication and make your controller agnostic to the implementation of the service.
There may already be a library that exists that does this that avoids using the heavy requirement of jQuery.
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
}
}]);
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.)