app.controller('AdminUserCtrl', function ($scope, $controller, $location, $http, $rootScope, $pouchDB, $state, $stateParams) {
$controller('AdminCtrl', {$scope: $scope});
console.log("AdminUser Controller reporting for duty.");
$scope.items = {};
$pouchDB.startListening();
// try to call
$pouchDB.getUsers();
console.log($pouchDB.getUsers());
// Listen for changes which include create or update events
$rootScope.$on("$pouchDB:change", function (event, data) {
$scope.items[data.doc._id] = data.doc;
$scope.$apply();
});
// Listen for changes which include only delete events
$rootScope.$on("$pouchDB:delete", function (event, data) {
delete $scope.items[data.doc._id];
$scope.$apply();
});
// Look up a document if we landed in the info screen for editing a document
if ($stateParams.documentId) {
$pouchDB.get($stateParams.documentId).then(function (result) {
$scope.inputForm = result;
});
}
app.service("$pouchDB", ["$rootScope", "$q", function ($rootScope, $q) {
var database;
var changeListener;
this.setDatabase = function (databaseName) {
database = new PouchDB(databaseName);
};
this.getUsers = function () {
return database.query({
map: function (doc, emit) {
if (doc.type === "user") {
emit(doc._id, doc);
}
}
});
};
this.startListening = function () {
changeListener = database.changes({
live: true,
include_docs: true
}).on("change", function (change) {
if (!change.deleted) {
$rootScope.$broadcast("$pouchDB:change", change);
} else {
$rootScope.$broadcast("$pouchDB:delete", change);
}
});
};
I trying to create view / query db ... but nothing happens ...
Can anyone provide example how to create view in angularjs-pouchdb ?
console.log($pouchDB.getUsers());
return:
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
Follow the docs, you want something that looks like . . .
app.service("$pouchDB", ["$rootScope", "$q", function ($rootScope, $q) {
var instance = {};
instance.database = null;
instance.changeListener = null;
instance.setDatabase = function (databaseName) {
this.database = new PouchDB(databaseName);
};
instance.getUsers = function () {
return this.database.query({
map: function (doc, emit) {
if (doc.type === "user") {
emit(doc._id, doc);
}
}
});
};
instance.startListening = function () {
this.changeListener = this.database.changes({
live: true,
include_docs: true
}).on("change", function (change) {
if (!change.deleted) {
$rootScope.$broadcast("$pouchDB:change", change);
} else {
$rootScope.$broadcast("$pouchDB:delete", change);
}
});
};
return instance;
}]);
Related
Im trying to add another function to my controller but it keeps breaking the controller.
here is my code:
.controller('ClimbController', [
'$scope', '$stateParams', 'Climbs', function(
$scope, $stateParams, Climbs) {
var climb_id = $stateParams.climbId;
var areaId = $stateParams.areaId;
if (!isNaN(climb_id)) {
climb_id = parseInt(climb_id);
}
if (!isNaN(areaId)) {
areaId = parseInt(areaId);
}
$scope.selected_ = {};
$scope.items = [];
$scope.details = true;
// looping though all data and get particular product
$scope.selectClimb = function(areas){
areas.forEach(function(data) {
if(data._id == climb_id){
$scope.selected_ = data;
}
});
}
// get all posts // try some function to get a single produt from server
$scope.getPosts = function(){
Climbs.getPosts()
.success(function (data) {
// data = feed.json file
var climbs = [];
data.areas.map(function(area) {
if (area._id === areaId) {
climbs = area.climbs;
}
});
$scope.selectClimb(climbs);
})
.error(function (error) {
$scope.items = [];
});
}
$scope.getPosts();
}
])
And I ned to add this to it:
.controller('MyCtrl', function($scope, $ionicModal) {
$ionicModal.fromTemplateUrl('test-modal.html', {
scope: $scope,
animation: 'slide-in-up'
}).then(function(modal) {
$scope.modal = modal;
});
$scope.openModal = function() {
$scope.modal.show();
};
$scope.closeModal = function() {
$scope.modal.hide();
};
//Cleanup the modal when we're done with it!
$scope.$on('$destroy', function() {
$scope.modal.remove();
});
// Execute action on hide modal
$scope.$on('modal.hidden', function() {
// Execute action
});
// Execute action on remove modal
$scope.$on('modal.removed', function() {
// Execute action
});
});
When I try to add this to the code it breaks it. I nee to either add it as another function or whatever is needed to add it to the code.
Thanks so much
Assuming that you want to merge 'MyCtrl functions into ClimbController then
.controller('ClimbController', ['$scope', '$stateParams', 'Climbs','$ionicModal', function($scope, $stateParams, Climbs,$ionicModal) {
var climb_id = $stateParams.climbId;
var areaId = $stateParams.areaId;
if (!isNaN(climb_id)) {
climb_id = parseInt(climb_id);
}
if (!isNaN(areaId)) {
areaId = parseInt(areaId);
}
$scope.selected_ = {};
$scope.items = [];
$scope.details = true;
// looping though all data and get particular product
$scope.selectClimb = function(areas){
areas.forEach(function(data) {
if(data._id == climb_id){
$scope.selected_ = data;
}
});
}
// get all posts // try some function to get a single produt from server
$scope.getPosts = function(){
Climbs.getPosts()
.success(function (data) {
// data = feed.json file
var climbs = [];
data.areas.map(function(area) {
if (area._id === areaId) {
climbs = area.climbs;
}
});
$scope.selectClimb(climbs);
})
.error(function (error) {
$scope.items = [];
});
}
$scope.getPosts();
$ionicModal.fromTemplateUrl('test-modal.html', {
scope: $scope,
animation: 'slide-in-up'
}).then(function(modal) {
$scope.modal = modal;
});
$scope.openModal = function() {
$scope.modal.show();
};
$scope.closeModal = function() {
$scope.modal.hide();
};
//Cleanup the modal when we're done with it!
$scope.$on('$destroy', function() {
$scope.modal.remove();
});
// Execute action on hide modal
$scope.$on('modal.hidden', function() {
// Execute action
});
// Execute action on remove modal
$scope.$on('modal.removed', function() {
// Execute action
});
}])
I have a controller and factory like below and can easily handle success..But how can I handle errors?
Controller
app.controller("draftsCtrl", ["$scope", "DashboardFactory", function ($scope, DashboardFactory) {
DashboardFactory.drafts(function (successCallback) {
$scope.rooms listings= successCallback;
});
}]);
Factory
app.factory('DashboardFactory', function ($http) {
var DashboardFactory = {};
DashboardFactory.active_listings = function (successCallback) {
$http.get('active.json').success(successCallback);
}
DashboardFactory.inactive_listings = function (successCallback) {
$http.get('inactive.json').success(successCallback);
}
DashboardFactory.drafts = function (successCallback) {
$http.get('drafts.json').success(successCallback);
}
return DashboardFactory;
});
Instead of passing callbacks around, prefer proper promises workflow. For this make your service methods return promise objects:
app.factory('DashboardFactory', function ($http) {
var DashboardFactory = {};
DashboardFactory.active_listings = function () {
return $http.get('active.json');
}
DashboardFactory.inactive_listings = function () {
return $http.get('inactive.json');
}
DashboardFactory.drafts = function () {
return $http.get('drafts.json');
}
return DashboardFactory;
});
Then use promise API to handle success (then callback) and errors (catch):
app.controller("draftsCtrl", ["$scope", "DashboardFactory", function ($scope, DashboardFactory) {
DashboardFactory.drafts().then(function (response) {
$scope.rooms_listings = response.data;
})
.catch(function() {
console.log('Error ocurred');
});
}]);
"service" looks more elegantly in this case
function DashboardFactory($http) {
this.active_listings = function () {
return $http.get('active.json');
};
this.inactive_listings = function () {
return $http.get('inactive.json');
};
this.drafts = function () {
return $http.get('drafts.json');
};
});
DashboardFactory.$inject = ['$http'];
app.factory('DashboardFactory', DashboardFactory);
I am trying to get the "make sure modalInstance.result.then is executed" test in my code to pass. Right now it says Expected [ undefined, 'http://www.link1.com', 'http://www.link2.com', 'http://www.link3.com' ] to contain 'http://www.pressboardmedia.com' I believe this has something to do with the promise needing to be mocked so it passes along the campaignLink but I am unsure if this is the problem and cannot seem to get it to work regardless. please let know if you have any ideas.
Thanks!
Controller File
angular.module('pb.campaignLinks.controllers')
.controller('CampaignLinksController', ['$scope', '$timeout', '$modal', '$stateParams', 'global', 'campaignLinkService', function ($scope, $timeout, $modal, $stateParams, global, campaignLinkService) {
$scope.init = function (currentView) {
$scope.partialViews = {
campaignLinkList: "/app/campaignLinks/views/_list.html",
};
$scope.currentView = currentView;
$scope.getCampaignLinks(currentView, 10);
};
$scope.getCampaignLinks = function (currentView, length, continuationToken) {
// When loading list items, display loading image
if ($scope.campaignLinks) $scope.campaignLinks.loading = true;
var promiseObj = null;
if (currentView.campaignId && currentView.campaignId !== 0 && !currentView.buyRequestId) {
promiseObj = campaignLinkService.getCampaignLinks(global.activeOrganizationId, currentView.campaignId, length, continuationToken)
} else if (currentView.campaignId && currentView.buyRequestId && currentView.campaignId !== 0 && currentView.buyRequestId !== '') {
promiseObj = campaignLinkService.getCampaignBuyRequestLinks(global.activeOrganizationId, currentView.campaignId, currentView.buyRequestId, length, continuationToken);
} else if (currentView.webSiteId && currentView.buyRequestId && currentView.webSiteId !== 0 && currentView.buyRequestId !== '') {
promiseObj = campaignLinkService.getWebSiteBuyRequestLinks(global.activeOrganizationId, currentView.webSiteId, currentView.buyRequestId, length, continuationToken);
}
if (promiseObj) {
promiseObj.then(function (data) {
// If there are already some campaign links being displayed, add newly loaded list to the end
if ($scope.campaignLinks) {
$scope.campaignLinks.continuationToken = data.continuationToken;
$scope.campaignLinks.total += data.total;
$.each(data.items, function (index) {
$scope.campaignLinks.items.push(data.items[index]);
});
} else {
// Otherwise add loaded list to scope
$scope.campaignLinks = data;
}
// When done loading, hide loading image
$scope.campaignLinks.loading = false;
});
}
};
$scope.openAddCampaignLink = function (campaignId) {
var modalOptions = {
templateUrl: '/app/campaignLinks/views/_add.html',
controller: 'AddCampaignLinksModalController',
resolve: {
campaignId: function () {
return campaignId;
}
}
};
var modalInstance = $modal.open(modalOptions);
modalInstance.result.then(function (campaignLink) {
// Add new item to list, otherwise wait for it to be loaded manually.
$scope.campaignLinks.items.unshift(campaignLink);
$scope.campaignLinks.total += 1;
}, function () {
console.log('Modal dismissed at: ' + new Date());
});
};
$scope.openRemoveCampaignLink = function (campaignId, campaignLink, index) {
var modalOptions = {
templateUrl: '/app/campaignLinks/views/_delete.html',
controller: 'RemoveCampaignLinksModalController',
resolve: {
campaignId: function () {
return campaignId;
},
campaignLink: function () {
return campaignLink;
}
}
};
var modalInstance = $modal.open(modalOptions);
modalInstance.result.then(function () {
// Splice the deleted item from the list without reloading all
$scope.campaignLinks.items.splice(index, 1);
$scope.campaignLinks.total -= 1;
}, function () {
console.log('Modal dismissed at: ' + new Date());
});
};
// Once everything is loaded, initialize controller
// init();
}]);
Test file:
describe('CampaignLinksController', function () {
//make module avalible to tests
beforeEach(module('pb.campaignLinks.controllers'));
beforeEach(module('ui.router'));
beforeEach(module('ui.bootstrap'));
var $controller;
var mockPromiseObj;
var length = 200;
var mockModal = {};
var mockCampaignLinks = {
total: 3,
items: ['http://www.link1.com', 'http://www.link2.com', 'http://www.link3.com']
};
var mockCurrentView = {};
var mockGlobal = { activeOrganizationId: 54 };
var continuationToken = {
nextRowKey: 'fdsf2',
nextPartitionKey: '5432gee'
};
var campaignDetails = {
campaignId: 453,
campaignLink: 'http://www.pressboardmedia.com',
index: 1
};
var mockCampaignLinkService = {
//move campaignDetails here
campaignLinks: {
total: 3,
//length here
items: ['http://www.link1.com', 'http://www.link2.com', 'http://www.link3.com']
},
//all but delete must return a promiseObj
getCampaignLinks: jasmine.createSpy('mockCampaignLinkService.getCampaignLinks').and.returnValue(mockPromiseObj),
getCampaignBuyRequestLinks: jasmine.createSpy('mockCampaignLinkService.getCampaignBuyRequestLinks').and.returnValue(mockPromiseObj),
getWebSiteBuyRequestLinks: jasmine.createSpy('mockCampaignLinkService.getWebSiteBuyRequestLinks').and.returnValue(mockPromiseObj),
deleteCampaignLink: jasmine.createSpy('mockCampaignLinkService.deleteCampaignLinks')
};
beforeEach(inject(function (_$controller_) {
$controller = _$controller_;
}));
beforeEach(inject(function ($rootScope) {
controller = $controller('CampaignLinksController',
{
$scope: scope,
$modal: mockModal,
//$stateParams: mockStateParams,
global: mockGlobal,
campaignLinks: mockCampaignLinks,
campaignLinkService: mockCampaignLinkService,
currentVeiw: mockCurrentView,
//promiseObj: mockPromiseObj
});
}));
describe('openAddCampaignLink()', function () {
var actualOptions;
var modalOptions = {
templateUrl: '/app/campaignLinks/views/_add.html',
controller: 'AddCampaignLinksModalController',
resolve: {
campaignId: jasmine.any(Function)
}
};
beforeEach(inject(function ($q) {
mockModal.open = function (options) {
actualOptions = options;
var defer = $q.defer();
defer.resolve();
return { result: defer.promise };
}
}));
it("make sure modalInstance.result.then is executed", function () {
scope.campaignLinks = mockCampaignLinkService.campaignLinks;
scope.openAddCampaignLink(campaignDetails.campaignId, campaignDetails.campaignLink, campaignDetails.index);
scope.$digest();
expect(scope.campaignLinks.total).toEqual(4);
expect(scope.campaignLinks.items).toContain(campaignDetails.campaignLink);
});
});
I think your problem is that the argument "campaignLink" that is supplied to your modalInstance.result.then function will always be undefined when you test this. The code that calls the modal close should be tested that it is supplying the campaignLink correctly. You only want to test that the proper code gets executed when the modal is closed. We do that by supplying a function that can be tested on it's own to the modalInstance.result.then call instead of doing an inline function so it can be tested easier.
Here's an example:
Here's the code that opens the modal:
$scope.editGradeClick = function () {
var modalInstance = $modal.open({
templateUrl: templateSrv.templateUrl('/Templates/App/Courses/CourseLessonGradeModal.html'),
controller: courseLessonGradeModalBootstrap,
backdrop: 'static',
keyboard: false,
resolve: {
data: $scope.editGradeModalResolve
}
});
modalInstance.result.then(
null,
$scope.editGradeModalDismissCallback
);
};
Notice how we supply a function $scope.editGradeModalDismissCallback instead of writting an inline function there for a modal dismiss. This allows us to test that logic in it's own test.
Now here is the test. We only care that the above function was called since we will be testing the specific function in it's own test. That happens at the last line in the test.
var $controllerConstructor, $scope, $q;
beforeEach(function () {
module('appModule');
inject(function ($controller, $rootScope, _$q_) {
$controllerConstructor = $controller;
$scope = $rootScope.$new();
$q = _$q_;
});
});
it('should execute $scope.editGradeModalDismissCallback when modal is dismissed', inject(function (templateSrv) {
var $modal = {};
$modal.open = function () {
var queryPromise = $q.defer();
queryPromise.reject();
return { result: queryPromise.promise };
};
$controllerConstructor('CourseLessonGradeListCtrl', { $scope: $scope, $modal: $modal, templateSrv: templateSrv});
spyOn($modal, "open").andCallThrough();
spyOn($scope, "editGradeModalDismissCallback");
$scope.editGradeClick();
$scope.$root.$digest();
expect($scope.editGradeModalDismissCallback).toHaveBeenCalled();
}));
I hope this helps you. In this example we are rejecting the promise because we are testing the modal dismiss not close, fyi...
I have a controller:
angular.module('mean').controller('LocationController', [
'$scope', '$location', '$rootScope', '$aside', '$routeParams', '$filter',
'ngTableParams', 'LocationService', 'UserService', 'CompanyService',
function ($scope, $location, $rootScope, $aside, $routeParams, $filter,
ngTableParams, LocationService, UserService, CompanyService) {
$rootScope.menuItem = 'locations';
$scope.contentTemplate = '/views/location/index.html';
$scope.locations = [];
$scope.current_location = null;
$scope.newLocation = {};
$scope.location_parent_id = $routeParams.location_parent_id;
$scope.validation_errors = [];
$scope.index = function() {
CompanyService.initialized.then(function() {
var company_id = CompanyService.getCompany()._id;
LocationService.list(company_id, $routeParams.location_parent_id).then(function(response) {
if(response.data.status === 'ok') {
$scope.locations = response.data.locations;
$scope.current_location = response.data.location || null;
} else {
alert('TBD');
}
});
});
$scope.tableParams = new ngTableParams({
page: 1,
count: 10,
}, {
total: $scope.locations.length,
getData: function($defer, params) {
var orderedData = params.sorting() ? $filter('orderBy')($scope.locations, params.orderBy()) : $scope.locations;
orderedData = params.filter() ? $filter('filter')(orderedData, params.filter()) : orderedData;
$scope.locations = orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count());
params.total(orderedData.length);
$defer.resolve($scope.locations);
}
});
}
$scope.addLocationModal = function() {
$scope.location_types = ['warehouse', 'section', 'row', 'shelf', 'bin'];
$aside({
scope: $scope,
template: '/views/location/addLocationAside.html',
show: true
});
}
$scope.createLocation = function() {
$scope.newLocation.company_id = CompanyService.getCompany()._id;
LocationService.create($scope.newLocation).then(function(response) {
if(response.data.status === 'ok') {
$scope.$hide();
$scope.index();
} else {
$scope.validation_errors = response.data.error;
}
});
}
}
]);
In the modal, I have a form, that when submitted, calls createLocation function. If the location is created successfully, I want the modal to close and the index to run and re-update the list. But that doesn't seem to happen. I think it's a $scope issue, but I'm not sure what.
Without any more details, it's really hard to tell the problem. So here are some guesses:
scope apply
If LocationService doesn't handle $scope.$apply, you might need to call it in the callback inside createLocation for the changes to take effect. Example:
$scope.createLocation = function() {
$scope.newLocation.company_id = CompanyService.getCompany()._id;
LocationService.create($scope.newLocation).then(function(response) {
$scope.$apply(function () {
if (response.data.status === 'ok') {
$scope.$hide();
$scope.index();
} else {
$scope.validation_errors = response.data.error;
}
});
});
};
You may also need to to do that in your $scope.index method, inside the LocationService.list callback.
initialized is only resolved once
It's possible that the CompanyService.initialized promise is only resolved once, at the loading of the app, so you aren't actually updating $scope.locations after closing the modal. I'd change that to:
var isCountryServiceInitalized = false;
$scope.index = function() {
function updateLocations() {
var company_id = CompanyService.getCompany()._id;
LocationService.list(company_id, $routeParams.location_parent_id).then(function(response) {
if (response.data.status === 'ok') {
$scope.$apply(function () { // you don't need this if LocationService already calls $scope.$apply
$scope.locations = response.data.locations;
$scope.current_location = response.data.location || null;
});
} else {
alert('TBD');
}
});
}
if (!isCountryServiceInitalized) {
CompanyService.initialized.then(function () {
isCountryServiceInitalized = true;
updateLocations();
});
} else {
updateLocations();
}
...
};
ngTable reload
It looks like you are using ng-table. You probably need to reload the table after updating $scope.locations. Use:
$scope.tableParams.reload();
I am pretty certain I'm following all the rules:
$get() is defined.
injecting properly into the controller
configuring in the initial app def before it's instantiated
Here is a fiddle
angular.module('app', function($httpProvider, $locationProvider, MockServiceProvider) {
delete $httpProvider.defaults.headers.common['X-Requested-With'];
$locationProvider.html5Mode(false);
MockServiceProvider.enableMocks(true);
})
.provider('MockService',['$http', '$q', function ($http, $q) {
this.mocksEnabled = false;
this.enableMocks = function(val) {
mocksEnabled = val;
};
this.$get = function() {
var _mock_getNext = function() {
return {
'status' : {
'type': 'OK',
'msg': null
},
'data': {
'id': 123456789
}
};
};
return {
getData : function() {
if(mocksEnabled) {
return _mock_getNext;
} else {
return "Real Data";
}
}
};
};
}])
.controller('Main', function(MockService) {
$scope.maybe_mock_data = MockService.getData();
});
The $http and $q injections for the provider should be on the $get method of the provider, not on the constructor of the provider.
Fiddle: http://jsfiddle.net/pvtpenguin/UAP29/1/
.provider('MockService',function () {
this.mocksEnabled = false;
this.enableMocks = function(val) {
mocksEnabled = val;
};
this.$get = ['$http', '$q', function($http, $q) {
var _mock_getNext = function() {
return {
'status' : {
'type': 'OK',
'msg': null
},
'data': {
'id': 123456789
}
};
};
return {
getData : function() {
if(this.mocksEnabled) {
return _mock_getNext;
} else {
return "Real Data";
}
}
};
}];
})
Other minor problems:
$scope was not injected into the controller
In the getData function of the service, mocksEnabled needed to be this.mocksEnabled