Using $uibModal from a factory - javascript

I've been playing around with using uibModal from a factory instead of using it from within my controller. The dialog comes up, and the field data is returned to the service when OK is clicked, but, I don't know how to get the data back to my controller, where it will be added to my model Any pointers?
Here is my factory code:
'use strict';
angular.module('ngTableScopeApp')
.factory('DialogService', function($uibModal){
var DialogService = {};
DialogService.newObj = {};
DialogService.addNewItem = function(template, $q){
this.modalInstance = $uibModal.open({
templateUrl: template,
controller: function($scope, $uibModalInstance){
$scope.ok = function () {
$uibModalInstance.close($scope);
return this.newObj;
};
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
return null;
};
}
});
};
return DialogService;
});
Here is the controller code:
'use strict';
/**
* #ngdoc function
* #name ngTableScopeApp.controller:MainCtrl
* #description
* # MainCtrl
* Controller of the ngTableScopeApp
*/
angular.module('ngTableScopeApp')
.controller('MainCtrl', function (NgTableParams, DummyData, DialogService) {
var self = this;
self.data = DummyData.generateData(1);
var createUsingFullOptions = function() {
var initialParams = {
count: 10 // initial page size
};
var initialSettings = {
// page size buttons (right set of buttons in demo)
counts: [5, 10, 25, 50],
// determines the pager buttons (left set of buttons in demo)
paginationMaxBlocks: 13,
paginationMinBlocks: 2,
dataset: self.data //DummyData.generateData(1)
};
return new NgTableParams(initialParams, initialSettings);
};
self.customConfigParams = createUsingFullOptions();
self.addNewItem = function(){
DialogService.addNewItem('views/addNewItem.html', self);
};
});

You could use close method available on $uibModalInstance service, in which you can pass data while closing a popup. And then you can utilize result promise object which does gets called when modal gets closed. Whatever data passed from $uibModalInstance.close method is available there. Make sure you are returning promise returned by $uibModal.open method.
Factory
DialogService.addNewItem = function(template, $q){
this.modalInstance = $uibModal.open({
templateUrl: template,
controller: function($scope, $uibModalInstance){
$scope.ok = function () {
$uibModalInstance.close({ data: 'OK Called' });
};
$scope.cancel = function () {
$uibModalInstance.close({ data: 'Cancel Called' });
};
}
});
};
return this.modalInstance;
};
Controller
DialogService.addNewItem('views/addNewItem.html', self)
.result.then(function(data) {
console.log("data", data); // print { data: 'MyCustomData' }
});
Modal Controller
$scope.cancel = function () {
$uibModalInstance.close({data: 'MyCustomData'});
};

Related

Undefined scope variable in AngularJS app

I am trying to set a Boolean property on an element in my array object, which I have in my scope.
In the code given below, when I try to set tasks[id].deleted = true, I get the following error.
angular.js:12798 TypeError: Cannot set property 'deleted' of undefined
at Scope.$scope.delete (main.js:54)
Where am I going wrong?
My whole code file is:
angular.module('ngMaterialTaskListApp')
.controller('MainCtrl', function ($scope, $mdDialog, TaskService) {
// Model from which View populates data
$scope.tasks = [];
console.log($scope.tasks);
$scope.showAddDialog = function (ev) {
$mdDialog.show({
controller: DialogController,
templateUrl: '../views/add-dialog-template.html',
parent: angular.element(document.body),
targetEvent: ev,
clickOutsideToClose: true,
fullscreen: true, //Only for xs and sm screen sizes
locals: { //For DialogController, as tasks
tasks: $scope.tasks
}
});
};
/*----------- Function to delete items onClick of delete icon -----------*/
$scope.delete = function (id) {
console.log($scope.tasks[id]);
console.log(id);
// console.log($scope.tasks[id].name);
$scope.tasks[id].deleted = true;
};
/*----------- DialogController function -----------*/
function DialogController($scope, $mdDialog, tasks) {
$scope.task = {};
$scope.hide = function () {
$mdDialog.hide();
//TODO Add a message as to what happened
};
$scope.cancel = function () {
$mdDialog.cancel();
//TODO Add a message as to what happened
};
/*----------- Method show the add dialog -----------*/
$scope.addData = function () {
if (null !== $scope.task.name && null !== $scope.task.description) {
/*----------- Using moment.js to parse date and time -----------*/
$scope.task.date = moment($scope.task.date, '').format('DD MMM YYYY');
$scope.task.time = moment($scope.task.time, '').format('h:mm a');
$scope.task.done = false; // Every new task is pending!
$scope.task.deleted = false; // Every new task exists!
var GlobalID = Date.now();
console.log(GlobalID);
$scope.task.id = GlobalID;
/*----------- Performing http POST -----------*/
TaskService.postTask($scope.task);
/*----------- Pushing to tasks object in $scope of MainCtrl -----------*/
// Have to update tasks again
tasks.push($scope.task);
$scope.hide();
console.log(tasks); //DEBUGGING
} else {
//TODO ADD INVALID/NULL DATA WARNING
}
};
};
// DEPRECATED - USED FOR DATA WHEN SERVER NOT AVAILABLE
TaskService.getTasks().then(function (response) {
$scope.tasks = response.data.tasks;
}, function (error) {
console.log(error + "This");
});
//USING THIS TO GET DATA FROM SERVER
TaskService.getAllTasks().then(function (response) {
// console.log(response.data);
$scope.tasks = response.data;
console.log($scope.tasks);
});
});
How is your html? I bet is like this inside a button in ng-repeat:
ng-click="delete(task.id)"
Try putting like this:
ng-click="delete($index)"

Pass value from provider to controller in angularJs

I'm trying get data from db to UI. Url given via provider is getting the data.
Controller in controller DetailsProvider.getDashboardDetails() is getting null.
var appmod = angular.module('project.DetailDashboardController', []);
appmod.controller("DetailDashboardController", ['$rootScope', '$scope', '$state', 'DetailsProvider',function($rootScope, $scope, $state,DetailsProvider) {
console.log("DetailDashboardController --- ");
$scope.DetList= DetailsProvider.getDashboardDetails()
}]);
})(window, window.angular);
provider which will call the list
(function(angular) {
var appmod = angular.module('project.DetailsServiceProvider', []);
appmod.provider('DetailsProvider', function() {
this.$get = ['_$rest', function DetailServiceFactory(_$rest) {
return new DetailsProvider(_$rest);
}];
});
function DetailsProvider(_$rest) {
this._$rest = _$rest,
this.getDashboardDetails = function(_callback, _data) {
var newData = null;
_$rest.post({
url: window.localStorage.getItem('contextPath') +'home/listdetail',
data: {} ,
onSuccess:_callback
}
});
}
};
})(window.angular);
Thanks in advance for any kind of reply!
You should return promise from your service method and do thenable in your controller.
Root Cause : your are returning the newData which will initalized later after completing the ajax call.Before completing it,you are returning the same variable which will be always null.
In provider,
(function(angular) {
var appmod = angular.module('project.DetailsServiceProvider', []);
appmod.provider('DetailsProvider', function() {
this.$get = ['_$rest', function DetailServiceFactory(_$rest) {
return new DetailsProvider(_$rest);
}];
});
function DetailsProvider(_$rest) {
this._$rest = _$rest,
this.getDashboardDetails = function(_callback, _data) {
var newData = null;
_$rest.post({
url: window.localStorage.getItem('contextPath') +'home/listdetail',
data: {} ,
onSuccess:_callback
}
});
}
};
})(window.angular);
and in controller,
$scope.list = function() {
DetailsService.getDashboardDetails(function(data){
varr holdIt = data.data.DList;
});
};

Angular JS UT: Controller having service returning $resource methods

I am writing a unit test for my angular controller; which is receiving $resource object from service.
However unit test is failing saying that "Action.query(success)' is not a function.
Looking forward for your comments.
PhantomJS 1.9.8 (Windows 8 0.0.0) ActionController Action controller getList() call should return an instance of array FAILED
TypeError: '[object Object]' is not a function (evaluating 'Action.query(success)')
action.controller.js
(function() {
'use strict';
angular
.module('app.action')
.controller('ActionController', ActionController);
ActionController.$inject = ['$sce', 'ActionService'];
/* #ngInject */
function ActionController($sce, $state, $stateParams, logger, exception,
moduleHelper, httpHelper, actionService) {
var vm = this;
var Action = null;
vm.title = 'action';
vm.data = []; /* action list model */
vm.getList = getList;
activate();
////////////////
function activate() {
Action = actionService.action();
}
/**
* Provides list of actions.
* Used from list.html
*/
function getList() {
var data = Action.query(success);
function success() {
vm.data = data._embedded.actions;
return vm.data;
}
}
}
})();
action.service.js
(function () {
'use strict';
angular
.module('app.action')
.service('ActionService', ActionService);
ActionService.$inject = ['$resource'];
/* #ngInject */
function ActionService($resource) {
var module = 'action';
var exports = {
action: action
};
return exports;
////////////////
/**
* Provides $resource to action controller
* #returns {Resources} Resource actions
*/
function action() {
return $resource('app/actions/:id', {id: '#id'}, {
query:{
method: 'Get',
isArray: false
},
update: {
method: 'PUT'
}
});
}
}
})();
action.controller.spec.js
/* jshint -W117, -W030 */
describe('ActionController', function() {
var controller;
var mockActions = mockData.getMockActions();
var mConfig = mockActions.getConfig();
var mockService = function() {
var list = [{
'id' : 1,'name' : 'CREATE'
},{
'id' : 2,'name' : 'VIEW'
}];
return {
query: function() {
return list;
},
get: function() {
return list[0];
},
save: function(action) {
var length = list.length;
list.push(action);
return ((length + 1) === list.length);
},
update: function(action) {
return true;
}
};
}
beforeEach(function() {
bard.appModule('app.action');
bard.inject('$controller', '$q', '$rootScope','ActionService');
});
beforeEach(function () {
bard.mockService(ActionService, {
action: function() {
return {
query: $q.when(mockService.query()),
get: $q.when(mockService.get()),
save: function(action) {
return $q.when(mockService.save(action));
},
update: function(action) {
return $q.when(mockService.update(action));
},
};
},
_default: $q.when([])
});
controller = $controller('ActionController');
$rootScope.$apply();
});
bard.verifyNoOutstandingHttpRequests();
describe('Action controller', function() {
it('should be created successfully', function () {
expect(controller).to.be.defined;
});
describe('getList() call', function () {
it('should have getList defined', function () {
expect(controller.getList).to.be.defined;
});
it('should return an instance of array', function () {
/* getting an error here*/
expect(controller.getList()).to.be.insanceOf(Array);
});
it('should return an array of length 2', function () {
expect(controller.getList()).to.have.length(2);
});
});
});
});
});
The ordering of the values in the $inject array must match the ordering of the parameters in ActionController.
ActionController.$inject = ['$sce', 'ActionService'];
/* #ngInject */
// 'actionService' must be the second parameter in the 'ActionController' function.
function ActionController($sce, actionService, $state, $stateParams, logger, exception,
moduleHelper, httpHelper) {
var vm = this;
var Action = null;
// the rest of the code.
You can find out more here: Angular Dependency Injection

revealing module pattern & variable scope -> public object undefined after async call returns

I have an Angular controller, which appeared to be working fine. I can console log the user variable inside of the service call, and it contains the correct data. However in my test, I can console log the controller and verify the user object is there, but it is empty. It really seems like initialize is trying to store the variable after the local scope is destroyed, but it is very strange as I have another controller & test written in the exact same way working fine.
I have been iterating over this for two days, so if anyone has any leads, I would be most grateful.
function DetailAccountController (accountsService) {
'use strict';
var user = {};
initialize();
return {
user: user
};
/**
* Initialize the controller,
* & fetch detail for a single user.
*/
function initialize () {
// If the service is available, then fetch the user
accountsService && accountsService.getById('').then(function (res) {
user = res;
});
}
}
and a jasmine test:
describe('DetailAccountController', function () {
var ctrl = require('./detail-account-controller'),
data = [{
"email": "fakeUser0#gmail.com",
"voornaam": "Mr Fake0",
"tussenvoegsel": "van0",
"achternaam": "User0",
"straat": "Mt Lincolnweg0",
"huisnr": 0,
"huisnr_toev": 0,
"postcode": "0LW",
"telefoonr": "0200000000",
"mobielnr": "0680000000",
"plaats": "Amsterdam",
"id": "00000000"
}],
accountsServiceMock,
$rootScope,
$q;
beforeEach(inject(function (_$q_, _$rootScope_) {
$q = _$q_;
$rootScope = _$rootScope_;
accountsServiceMock = {
getById: function () {}
};
}));
it('should call the getById method at least once', function () {
spyOn(accountsServiceMock, 'getById').and.returnValue($q.defer().promise);
ctrl.call({}, accountsServiceMock);
expect(accountsServiceMock.getById.calls.any()).toBe(true);
expect(accountsServiceMock.getById.calls.count()).toBe(1);
});
it('should populate user data in the model', function () {
var deferred = $q.defer();
deferred.resolve(data);
spyOn(accountsServiceMock, 'getById').and.returnValue(deferred.promise);
var vm = ctrl.call({}, accountsServiceMock);
$rootScope.$apply();
expect(vm.user).toEqual(data);
});
});
Updated solution for the curious
function DetailAccountController (accountsService) {
'use strict';
var self = this;
self.user = null;
initialize();
return self;
/**
* Initialize the controller,
* & fetch detail for a single user.
*/
function initialize () {
accountsService && accountsService.getById('').then(function (res) {
self.user = res;
});
}
}
user = res affects local variable and has nothing to do with returned object.
It has to be either
accountsService && accountsService.getById('').then(function (res) {
angular.extend(user, res);
});
or
var obj = {
user: {}
};
initialize();
return obj;
function initialize () {
accountsService && accountsService.getById('').then(function (res) {
obj.user = res;
});
}

Angular Testing - promise not returning data

I can't see why vm.chartData in my HomeCtrl never gets populated with the data i've mocked to it in the beforeEach(). the console.log(scope.vm.chartData) returns undefined even while the other scope vars like graphLoading are defined and changed properly.
describe('HomeCtrl', function () {
var controller, scope, myService, q, $timeout;
beforeEach(module('dashboardApp'));
beforeEach(inject(function ($controller, $rootScope, $q, _$timeout_) {
controller = $controller;
scope = $rootScope.$new();
$timeout = _$timeout_;
myService = jasmine.createSpyObj('Chart', ['get']);
q = $q;
}));
describe('when returning promises', function () {
beforeEach(function () {
myService.get.and.returnValue(q.when( { result:
'Stuff'
}));
controller('HomeCtrl as vm', { $scope: scope, Chart: myService });
scope.$apply();
});
it('test dirty graph init', function () {
expect(scope.vm.graphLoading).toBe(true);
scope.vm.dirtyTestGraph();
scope.$digest();
$timeout.flush();
expect(scope.vm.graphLoading).toBe(false);
console.log(scope.vm.chartData);
});
});
});
relevent code from homectrl
vm.dirtyTestGraph = function() {
vm.graphTitle = 'Deposit Amount';
$timeout(function(){
Chart.get( { interval:'3h', type:'_type:deposit',
from:1416960000000, to:Date.now() } )
.then(function(chart){
vm.graphLoading = false;
vm.chartData = chart.data;
});
}, 2000);
};
and here is the return value of Chart.get in the Chart factory
return $q.all([chartData])
.then(function(data){
var graphData = data[0].data.facets[0].entries;
var newData = [];
graphData.forEach(function(element){
var newElem = {
time: element.time,
deposits: element.total.toFixed(2)
};
newData.push(newElem);
});
return new Chart(newData);
});
Your controller code is looking for a data property in the object within the promise returned by Chart.get:
vm.chartData = chart.data;
But your test's stub is returning an object without a data property:
myService.get.and.returnValue(q.when({
result: 'Stuff'
}));
So vm.chartData gets assigned with undefined.

Categories