Access Angular model instance from external JS? - angularjs

My 'ProjectsCtrl' contains this function for adding a new project to a parent resource:
$scope.addProject = function(client){
$scope.client = client;
$scope.newProject.client_id = client.id;
project = Project.save($scope.newProject);
$scope.newProject = {};
}
The 'client' argument is taken from the view wherein I have an ng-submit="addProject(client)" within an ng-repeat="client in clients" block.
In another .js file I am trying to get reference to that client instance in order to update the view after pushing some data using server side events. Here is that code:
var pSource = new EventSource('/administration/projects/events');
pSource.addEventListener('projects.create', function(e){
var project = $.parseJSON(e.data);
var projectCtrl = angular.element($(".project-list")).scope();
projectCtrl.$apply(function(){
projectCtrl.client.projects.push(project);
});
});
The problem is that the project is always appended onto the first client instance, and not the one being passed to the addProject() function.
If I do client.projects.push(project); within the controller, then it works correctly. How can I get a reference to that client instance from outside of the controller?

The approach depends on the context:
If you are trying to update a model from another angular controller you can use angular services (angular services are basically singletons in the application) in order to have the same model reference
If you are trying to call a method from outside the angular scope you can either:
2.1. publish your controller function reference to a global namespace (not the best choice)
2.2. use any event dispatching mechanism and call $scope.apply(function() {manipulate your model }); on event listener

I ended up passing the $index of the parent resource as a model attribute on the child object and using that to push to the correct position.
e.g.
var clientCtrl = angular.element($(".client-list")).scope();
var project = $.parseJSON(e.data);
var projectCtrl = angular.element($(".project-list")).scope();
projectCtrl.$apply(function(){
clientCtrl.clients[project.client_ix].projects.push(project);
});

Related

Pass multiple scope members from controller to angular service

I am new to AngularJS world. I am developing AngularJS SPA application. I have a controller paymentController which is going to use an angular custom service paymentService. The paymentController $scope has multiple members like billerId, billAccount, paymentAmount, etc. I want to pass all/most of these members to the function exposed by angular service. I don't know what is the best way to do so. My code is given below:
app.controller("paymentController", function ($scope, $rootScope, paymentService) {
$scope.billerId;
$scope.billAccount;
$scope.paymentAmount;
$scope.feeAmount=1.0;
$scope.platform = 1;
$scope.makePayment = function(){
paymentService.makePayment(/*what should be passed to this function*/);
}
});
Please suggest me the ideal way.
Better way is to create a object with all those properties and pass the object,
$scope.bill ={};
$scope.bill.billerId;
$scope.billAccount;
$scope.bill.paymentAmount;
$scope.bill.feeAmount=1.0;
$scope.bill.platform = 1;
$scope.makePayment = function(){
paymentService.makePayment($scope.bill);
}

Angularjs : Using common service in different modules

I am trying to use the same service for different modules. There are many modules so i tried to inject them in a parent module. Something like this:
var app=angular.module('myapp',['module_1','module_2',....,'module_n']);
var module_1=angular.module('myapp1',[]);
var module_2=angular.module('myapp2',[]);
var module_3=angular.module('myapp3',[]);
.
.
.
var module_n=angular.module('myappN',[]);
and the service which is common to all the n modules is like this:
.service('myService',function(){
...doing something here...
});
Now I am not able to figure out how to use this service for all the submodules.
With which module should I associate this service ?
I tried doing app.service('myService',function(){...}), but it did'nt work.
Where am I going wrong?
EDIT 1:
Moreover I am trying to share a variable with all these submodules using the service. I am not sure if, I am doing the right thing by using a service for sharing variable or should I use a Provider or Factory for this job.
EDIT 2:
I found these links, but I could not grasp the answer. Refer to them and please provide my answer
How to share a variable between multiple modules in AngularJS
Passing variable between controllers which are on different modules
Lets suppose you want to build a Service to share a certain variable between two Controllers. You should be able to use your Service doing the following:
MyService.js
// Lets suppose you want to share a certain variable between controllers
angular
.module('myApp')
.service('myService', function () {
// If you wish you can inject and use $scope
var vm = this;
// Variable to share
vm.sharedItem;
// Method to set a certain value into a variable
function setItem(item){
vm.sharedItem = item;
}
// Method to get that variable
function getItem(){
return vm.sharedItem;
}
// Exposing your methods
return {
setItem : setItem
getItem : getItem
}
});
SetController.js
angular
.module('myApp')
.controller('SetController', SetController);
// Inject your Service
function SetController(myService) {
var vm = this;
// variable used to set the value
vm.setMe = 'hello';
// Call `setItem()` method from `myService` -> sharedItem will get setMe value
myService.setItem(vm.setMe);
console.log("Set shared item "+vm.setMe);
};
GetController.js:
angular
.module('myApp')
.controller('GetController', GetController);
// Inject your Service
function SetController(myService) {
var vm = this;
// variable used to get shared the value
vm.getMe= null;
/* Call `getItem()` method from `myService` to get the shared
* value and assign it to `getMe`*/
vm.getMe = myService.getItem();
console.log("Got shared item "+vm.getMe);
};
I remind you can access this.var in your view using controllerName.var. It is a good solution to make sure you are using a certain controller. You can always use $scope if you wish.
I hope I've been helpful.

What is the better way to add office 365 javascript api library to angular js project?

Officejs library can be used inside angular controller as following way by adding library reference https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js to index page
function sendRequest() {
// Create a local variable that contains the mailbox.
var mailbox = Office.context.mailbox;
mailbox.makeEwsRequestAsync(getItemRequest(mailbox.item.itemId), callback);
}
function callback(asyncResult) {
var result = asyncResult.value;
var context = asyncResult.context;
// Process the returned response here.
}
is there any better way to handle these kind of libraries inside angular js project ?
Yeoman generater is there. it has option to create angular project
https://www.npmjs.com/package/generator-office

Firebase syncObject is showing redundant error in my Angular controller

I am building an app for a client who has, as one of their data sets a master list of all their members. I have the data coming in from Firebase and everything runs peachy, but it's not that DRY I am now realizing. I would like to use some of the data from the membership set in other views within the site. I copied the code listed below into other controllers that I need to have access to it and although everything works, my IDE (RubyMine) shows the 'syncObject' as redundant.
So, my question is, if there's a way to code it better and dryer to be used in other views? Thank you for your time.
.controller( 'MembershipCtrl', function MembershipCtrl( $scope, $firebase ) {
var ref = new Firebase("https://myid.firebaseio.com/members");
var sync = $firebase(ref);
var syncObject = sync.$asArray();
$scope.members = syncObject;
});

How can I test an AngularJS service from the console?

I have a service like:
angular.module('app').factory('ExampleService', function(){
this.f1 = function(world){
return 'Hello '+world;
}
return this;
})
I would like to test it from the JavaScript console and call the function f1() of the service.
How can I do that?
TLDR: In one line the command you are looking for:
angular.element(document.body).injector().get('serviceName')
Deep dive
AngularJS uses Dependency Injection (DI) to inject services/factories into your components,directives and other services. So what you need to do to get a service is to get the injector of AngularJS first (the injector is responsible for wiring up all the dependencies and providing them to components).
To get the injector of your app you need to grab it from an element that angular is handling. For example if your app is registered on the body element you call injector = angular.element(document.body).injector()
From the retrieved injector you can then get whatever service you like with injector.get('ServiceName')
More information on that in this answer: Can't retrieve the injector from angular
And even more here: Call AngularJS from legacy code
Another useful trick to get the $scope of a particular element.
Select the element with the DOM inspection tool of your developer tools and then run the following line ($0 is always the selected element):
angular.element($0).scope()
First of all, a modified version of your service.
a )
var app = angular.module('app',[]);
app.factory('ExampleService',function(){
return {
f1 : function(world){
return 'Hello' + world;
}
};
});
This returns an object, nothing to new here.
Now the way to get this from the console is
b )
var $inj = angular.injector(['app']);
var serv = $inj.get('ExampleService');
serv.f1("World");
c )
One of the things you were doing there earlier was to assume that the app.factory returns you the function itself or a new'ed version of it. Which is not the case. In order to get a constructor you would either have to do
app.factory('ExampleService',function(){
return function(){
this.f1 = function(world){
return 'Hello' + world;
}
};
});
This returns an ExampleService constructor which you will next have to do a 'new' on.
Or alternatively,
app.service('ExampleService',function(){
this.f1 = function(world){
return 'Hello' + world;
};
});
This returns new ExampleService() on injection.
#JustGoscha's answer is spot on, but that's a lot to type when I want access, so I added this to the bottom of my app.js. Then all I have to type is x = getSrv('$http') to get the http service.
// #if DEBUG
function getSrv(name, element) {
element = element || '*[ng-app]';
return angular.element(element).injector().get(name);
}
// #endif
It adds it to the global scope but only in debug mode. I put it inside the #if DEBUG so that I don't end up with it in the production code. I use this method to remove debug code from prouduction builds.
Angularjs Dependency Injection framework is responsible for injecting the dependancies of you app module to your controllers. This is possible through its injector.
You need to first identify the ng-app and get the associated injector.
The below query works to find your ng-app in the DOM and retrieve the injector.
angular.element('*[ng-app]').injector()
In chrome, however, you can point to target ng-app as shown below. and use the $0 hack and issue angular.element($0).injector()
Once you have the injector, get any dependency injected service as below
injector = angular.element($0).injector();
injector.get('$mdToast');

Resources