Recently I have begun to integrate AngularJS in project.
Before I have written many prototypes and single functions in JavaScript, for example (Node.js + socket.io functionality).
Today I a have trouble communicating AngularJS with clear JavaScript:
JS:
socket.on('message', function (data) {
showSystemMessage();
}
function showSystemMessage(message) {
// Increment here AngularJS $scope.messagesCnt++ ?;
}
AngularJS:
.controller('MessagesController', ['$scope', function($scope) {
$scope.messagesCnt = 0;
}])
HTML:
<div>{{messagesCnt}}</div>
Please, attention to method: showSystemMessage()
Ideally, You should follow what #Yaseer has said, but i see, that you're using Socket IO native implementation [No angular Wrapper around].
Hence, you have two solutions :
Use Angular Socket IO
Access Angular Controller from the native javascript :
For this you must have an element with an identifier ID. then you can use the id to access the associated scope.
angular.element("#your-identifier-id-here").scope().messagesCnt++;
Write your socket listener code inside controller
function appcontroller($scope){
socket.on('message', function (data) {
showSystemMessage();
}
function showSystemMessage(message) {
$scope.$apply(function(){
// Increment here AngularJS $scope.messagesCnt++ ?;
});
}
}
If you function showSystemMessage is outside the controller scope, there is no way you can update the scope variable messagesCnt. (There are but not straight forward.)
Instead this function of yours should reside in an angular service instead, and then on whatever event you want you could broadcast a message from your service to your controller to update its count value.
Related
I'm new in AngularJS and I'm doing a refactor of an AngularJS application and I noticed that there is a single controller file with a lot of functions that manipulate and set scope variables.
Following an example:
test.controller('testCtrl', function testCtrl($scope) {
$scope.init_filters = function() {
$scope.filter_1 = [];
$scope.filter_2 = [];
$scope.filter_3 = [];
$scope.filter_4 = [];
$scope.filter_5 = [];
};
$scope.showChanges = function() {
if ($scope.item_list.length > 0) {
$scope.messages = [];
for (var i = 0; i < $scope.item_list.length; i++) {
$scope.messages.push($scope.item_list[i].message);
}
$scope.another_function();
}else{
// other stuff
}
};
//other functions like these
}
So, I would like to split these functions in multiple JS files. I searched about this problem and I found that in a lot of case is used a service. But I think that this is not my case, because I need to working on directly on the controller's scope.
I mean, I don't want a separated function that get as parameters some scope variables and return the variable.
So, what is the best practices for doing something like this? is it possible?
If you want to use multiple files then split the definition to multiple files by passing the scope to another method and then define the rest of methods there.
File1
app.controller('CtrlOne', function($scope){
app.expandControllerCtrlOne($scope);
});
File2
app.expandControllerCtrlOne = function($scope)
{
}
Check this video
As you said the code you found for controller is large one so there are multiple ways in angular js that you can implemented the separation of code.
I will suggest you to go with following approach:
Use service to add those code in it which you need in other places as well and you know that this code does not require scope object..
Use factory to add some Utility kind of functions. The collection of logic which does not require scope object again...
As controller code is too large, I think View/UI of same also being as per wrote...
So for this you can go with creating directives for section in view..
Where-ever you think this peace of view section can be separate and standalone logical functionality that you can move into directive.
There are three ways to create directive with scopes:
A. Shared Scope B. Isolated Scope C: shared and Isolated scope
In this ways may you can at-least make your controller code readable and looks modular.
Let say::
module.controller('longRunController', function() {
#TYPE 1 code
// some code which fetch dat from API
// some code which save variable and objects which can used in another controller or directives
// some code which need to passed to other controller even after route changes
#TYPE 2
// some code which is only related this controller but has some bussiness logic
// some code which is a kind of utility functino
#TYPE 3
// all $scope related variable $watch, $scope and related variables
// some code of perticular section of which VIEW which handle by this controller
});
Consider in above patter your controller code has:
So type 1 code can be moved to Service
type 2 code can be moved to factory
type 3 code can be move to directives
you can pass $scope as a parameter to the external function.
And because you just use the objectreference, all changes you made in your external functions are made on the $scope object from your controller.
test.controller('testCtrl', function testCtrl($scope)
{
showChanges($scope);
});
...
function showChanges(scope)
{
scope.param1 = "Hello World";
}
I have an alright knowledge of angularjs but I am more of a R programmer and I have therefore being experimenting with OpenCPU js library.
One thing I can't get my head around is why I can't assign the output from a simple API request to the public OpenCPU server, rnorm(n = 2) function, to an angular $scope. What baffles me is that I can use jquery to assign the returned json via ID for example.
From what I understand it is best practice not to mix jquery into the angular controller. Am I right in thinking this?
Working with Jquery
app.controller('rCtrl', function($scope){
req = ocpu.rpc('rnorm',{
n : 2
}, function(output){$('#output').text(output)});
})
Not Working $scope
app.controller('rCtrl', function($scope){
req = ocpu.rpc('rnorm',{
n : 2
}, function(output){$scope.normalValues = output)});
})
Since you are using a non-angular tool you are assigning $scope.normalValues outside of the Angular digest loop. Use a $scope.apply() to fix this:
app.controller('rCtrl', function($scope){
req = ocpu.rpc('rnorm',{
n : 2
}, function(output){
$scope.$apply(function(){
$scope.normalValues = output;
});
)});
});
You can also just call $scope.$apply() right after you set your scope value but I personally like the callback syntax since it makes it easier to see why you use it.
I'm guessing it's because your function never triggers a $digest cycle - so you'd have to force one with $timeout
app.controller('rCtrl', function($scope, $timeout){
req = ocpu.rpc('rnorm',{
n : 2
}, function(output){
$timeout(function() { $scope.normalValues = output })
})
})
In Angular JS instead of using the service in a module, can I create Javascript functions outside the controller and call it when I want to?
For example:
var UrlPath="http://www.w3schools.com//angular//customers.php"
//this will contain all your functions
function testing_Model ($http){
var self=this;
self.getRecords=function(){
$http({
Method:'GET',
URL: UrlPath,
}).success(function(data){
self.record=data.records;
});
}
self.getRecords();
}
angular.module("myApp", []);
app.controller('myController', function ($scope, $http) {
$scope.testing_Model = new testing_Model();}
When I run the code above, it says "$http is not a function".
Thanks in advance.
You need to pass $http to this function...
$scope.testing_Model = new testing_Model($http);
Although it will work it obviously goes against the idea of Angular. You must inject your function as a service in your controller to write testable code, track dependencies and just respect other developers who will be going to support your project later.
I struggled to title this question but basically I'm just starting off with angular and am using ngMaterial. I have a toast created by using an angular factory
app.factory('notify', ['$mdToast', '$animate', function($mdToast, $animate) {
return {
showToast: function(msg) {
var toast = $mdToast.simple()
.content(msg)
.action('Close')
.highlightAction(false)
.position('top right');
$mdToast.show(toast).then(function() {
//
});
}
}
}]);
This works great if I have a button on the page that activates the toast however I have socket.io running as well with node monitoring redis for updates to pop up that notification. However I can't get it to work as I'm not quite sure how I can call that factory from within here
socket.on('notification.new', function (data) {
//call factory here to show toast
console.log(data);
});
I know if I have it on a controller I can do it by using
angular.element().scope().showToast(data)
But I don't want to create an element just to house the controller to call the function.
What I did to solve this issue is I attached one of the functions inside the controller to the window object. So something like
window.showToast = function(msg) {
var toast = $mdToast.simple()
.content(msg)
.action('Close')
.highlightAction(false)
.position('top right');
$mdToast.show(toast).then(function() {
//
});
Then, from within the socket io listener (or any raw javascript for that matter):
socket.on('notification.new', function (data) {
//call factory here to show toast
window.showToast(data); //or however you'd like
});
And that kind of worked for me. I know this is not the best approach but since this question didn't have any answers at all I thought I'll post a workaround that at least does the job done.
You need to get hold of Angular services to use Angular in a raw Javascript.
Refer to Call Angular JS from legacy code
angular.element(domElement).scope() to get the current scope for the element
angular.element(domElement).injector() to get the current app injector
angular.element(domElement).controller() to get a hold of the ng-controller instance.
In your case use injector service to get hold of your factory.
Update 1
$injector reference
I am trying to re-write an application using angular.js, but I still do not see how it works (more or less).
For instance. In my previous code, I had a function that was executed once everything was loaded that initialised variables, accessed for everyone in a window.variable style.
Now I want the same here.
My idea was to build a factory to return an object with all the variables, and then make that everyone had access to this object (somehow).
The questions are:
1- Am I right? I should initialise variables through a factory?
2- And how can I "call" this factory-method at the beginning of the code? with the module.run function?
Cheers,
I'd probably put the variables in a service, and then inject that into a wrapping angular controller. Any other controllers that you would want to have access to these 'global' variables would be nested under the wrapping controller, thus inheriting the variables.
var app = angular.module("app", []);
app.service("globVars", function () {
var vars = {};
vars.someVar = "a";
vars.someOtherVar = "b";
return vars;
});
app.controller("WrappingCtrl", function ($scope, globVars) {
$scope.globVars = globVars;
});
app.controller("NestedCtrl", function ($scope) {
console.log($scope.globVars.someVar); // => "a"
});
<html ng-app="app">
<div id="wrapper" ng-controller="WrappingCtrl">
<div class="nested" ng-controller="NestedCtrl">
{{globVars.someVar}}
</div>
</div>
</html>
I think you should avoid using global variables as much as you could
But if you have to use them, you are right, you can initialize them in module.run and add the module in the app dependencies
If you want to access some variables, you must see to $rootScope, because you can access $rootScope everywhere.
Also you must use angular config and run functions.
I advice to you don't use global scope, because it affects on app speed, memory leaks etc.