I have an AngularJS 1.2 app. My app has a controller that looks like this:
myApp.controller('MyController', ['$scope', '$rootScope', '$http',
function ($scope, $rootScope, $http) {
$scope.newItem_Click = function () {
var modalInstance = $modal.open({
templateUrl: 'item-dialog.html',
size: 'md',
controller: function ($scope, $modalInstance) {
$scope.item = { typeId: 7, id: '-1' };
$scope.saveItem = function (did) {
if ($scope.item.description) {
if ($scope.item.description.trim().length > 0) {
$scope.item.departmentId = did;
$modalInstance.close($scope.item);
}
} else {
alert('Please enter your description.');
}
};
$scope.cancelItem = function () {
$modalInstance.dismiss('cancel');
};
$scope.getItems = function (departmentId) {
var url = '/api/items?departmentId=' + departmentId;
return $http.get(url).then(
function (response) {
var results = response.data;
results.reverse();
var items = [];
var i = 0;
angular.forEach(results, function (item, key) {
var local = results[i].CreatedUTC;
results[i].CreatedOn = new Date(local);
items.push(item);
i = i + 1;
});
console.log(items);
$scope.items = items;
}
);
};
$scope.$on('list-updated', function () {
$scope.getItems($scope.item.id);
});
}
});
modalInstance.result.then(
function (item) {
var apiUrl = '/api/items';
apiUrl = apiUrl + '?typeId=' + item.typeId;
if (item.departmentId!== '-1') {
apiUrl = apiUrl + '&departmentId=' + item.departmentId;
}
apiUrl = apiUrl + '&content=' + item.description;
apiUrl = encodeURI(apiUrl);
$http.post(apiUrl).then(
function () {
$rootScope.$broadcast('list-updated');
}
);
}
);
};
}]);
For some reason, I can successfully save an item. The console.log(items) statement displays all of the items as I would expect. However, my view is not being updated. What am I doing wrong? I suspect its because I'm assigning $scope.items inside of the HTTP response. Yet, I'm not sure how to get around it.
I know this is not recommended. However, I am in crunch mode.
Related
How can I call $http.get every second to update my page?
var app = angular.module("CompanionApp", []);
app.controller('LoginController', function ($scope, $http) {
$scope.LoginSubmit = function() {
$http.get('/api/player/' + $scope.name)
.then(function(res) {
$scope.connected = res.data.connected;
$scope.health = res.data.health;
$scope.armour = res.data.armour;
})
};
});
Try $interval :
var app = angular.module("CompanionApp", []);
app.controller('LoginController', function ($scope, $http, $interval) {
var interval;
$scope.LoginSubmit = function() {
interval = $interval(function () {
$http.get('/api/player/' + $scope.name)
.then(function(res) {
$scope.connected = res.data.connected;
$scope.health = res.data.health;
$scope.armour = res.data.armour;
})
}, 1000);
};
$scope.stopCalls = function(){ // incase you want to stop the calls using some button click
$interval.cancel(interval);
}
});
In my application I am constantly updating displayed data which changes on the server using an interval, which loads whenever the controller loads. The controller loads together with the function in the interval when I navigate to a specific site and I would like it to stop when I navigate to another. The problem is that after some time of usage of the site, I end up with a bunch of intervals running and it just appears nasty. Here is the code of the controller:
angular
.module('myApp')
.controller('TaxiesController', ['$scope', '$location', '$routeParams', '$route', 'dataFactory', '$interval', function ($scope, $location, $routeParams, $route, dataFactory, $interval) {
console.log('TaxiesController loaded')
var cancel = {
name: 'Preklic',
price: 500
}
$scope.taxies = [];
$scope.taxi = {};
$scope.taxi.history = [];
taxi = {}
taxi.history = [];
$scope.getTaxies = () => {
dataFactory.getTaxies().then(function (response) {
$scope.taxies = response.data;
});
}
$scope.getTaxi = () => {
var id = $routeParams.id;
dataFactory.getTaxi(id).then(function (response) {
$scope.taxi = response.data;
});
}
$scope.removeTaxi = (id) => {
dataFactory.removeTaxi(id).then(function (response) {});
}
$scope.getTotal = (taxi) => {
var total = 0;
for (var i = 0; i < taxi.history.length; i++) {
var rent = taxi.history[i];
if (rent.price) total += rent.price;
}
return total;
}
$scope.disableTaxi = (taxi, id) => {
taxi.drivable = false;
dataFactory.updateTaxi(id, taxi).then(function (response) {
$scope.taxi = response.data;
$route.reload();
})
}
$scope.cancelTaxi = (taxi, id) => {
console.log('cancelling..')
taxi.available = true;
taxi.history.unshift(cancel);
dataFactory.updateTaxi(id, taxi).then(function (response) {});
}
var updateTaxies = () => {
console.log('Checking rent length')
dataFactory.getTaxies().then(function (response) {
$scope.taxies = response.data;
});
}
$interval(updateTaxies, 2000);
}]);
Just add this inside the controller:
var intervalListener = $interval(updateTaxies, 2000);
$scope.$on('$destroy', function() {
$interval.cancel(intervalListener);
});
$destroy is an event that will be fired when a scope is being destroyed. Here is the doc about it
I have an app which fetches data from a database on load.
Since the data in the database changes every few seconds, I would like to dynamically add the new data in the database into the table in the HTML page.
Any ideas on how to implement without reloading the controller?
The current code:
app.js
var app = angular.module('myApp', ['ui.bootstrap','countTo']);
app.filter('startFrom', function() {
return function(input, start) {
if(input) {
start = +start; //parse to int
return input.slice(start);
}
return [];
}
});
app.config(['$compileProvider', function($compileProvider) {
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|http?|file|data):/);
}]);
app.controller('customersCrtl', function ($scope, $http, $timeout) {
$scope.$emit('LOAD');
$scope.progressBar = { progress : 0 };
$http.get('ajax/getCustomers.php').success(function(data){
$scope.list = data;
$scope.currentPage = 1; //current page
$scope.entryLimit = 50; //max no of items to display in a page
$scope.filteredItems = $scope.list.length; //Initially for no filter
$scope.totalItems = $scope.list.length;
$scope.$emit('UNLOAD');
});
(function progress(){
if($scope.progressBar.progress < 100){
$timeout(function(){
$scope.progressBar.progress += 1;
progress();
},5);
}
})();
$scope.setPage = function(pageNo) {
$scope.currentPage = pageNo;
};
$scope.filter = function() {
$timeout(function() {
$scope.filteredItems = $scope.filtered.length;
}, 10);
};
$scope.sort_by = function(predicate) {
$scope.predicate = predicate;
$scope.reverse = !$scope.reverse;
};
});
app.controller('delayController',['$scope',function($scope){
$scope.$on('LOAD',function(){$scope.loading=true});
$scope.$on('UNLOAD',function(){$scope.loading=false});
}]);
app.controller("PostsCtrl", function($scope, $http, $timeout) {
$scope.progressBarScanned = { progressScanned : 0 };
(function tick() {
$http.get('ajax/scanStatus.php').
then(function(response) {
$scope.posts = response.data;
$scope.scanProgerss = $scope.posts[0].isScanning;
$scope.scanPercentage = $scope.posts[0].scanPercentage;
$scope.timeToFinish = $scope.posts[0].timeToFinish;
$scope.amountScanned = $scope.posts[0].amountScanned;
$scope.totalItemsToScan = $scope.posts[0].totalItemsToScan;
$scope.avgScanTimePerItem = $scope.posts[0].avgScanTimePerItem;
});
$timeout(tick, 1000);
})();
(function progressScanned(scanned){
if($scope.scanPercentage < 100){
$timeout(function(){
$scope.progressScanned.progress = 1;
progressScanned();
},5);
}
})();
});
//Modal
var ModalDemoCtrl = function ($scope, $modal) {
$scope.open = function (imageKey) {
$modal.open({
templateUrl: 'myModalContent.html',
backdrop: true,
windowClass: 'full',
controller: function ($scope, $modalInstance, data, imageKey) {
$scope.data='';
$scope.data = data;
$scope.getImage = function () {
return $scope.data[imageKey];
}
$scope.cancel = function () {
$modalInstance.dismiss('close');
};
},
resolve: {
data: function() {
// access outer controller scope by using $scope.$parent
return $scope.$parent.data;
},
imageKey: function() {
return imageKey;
}
}
});
}};
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'm using infinite-scroll and I want to request more data using $http. So next page / next 10 results etc.
This is my current working code (I put this in a factory as I read on another post somewhere that this was a good idea, I'm now thinking a service might be better but I'm not sure yet):
angular.module('hotels', [])
.factory('hotels', function($http) {
var hotels = {};
hotels.get = function(callback) {
$http.get('/php/hotels.php').success(function(data) {
callback(data);
});
};
return hotels;
});
angular.module('app', ['hotels', 'infinite-scroll'])
.controller('hotelsCtrl', function ($scope, hotels){
hotels.get(function (data) {
$scope.hotels = data.results;
})
});
How do I pass back a param page=3 and have the backend return more results?
I thought it might look something like this but its not working.:
angular.module('hotels', [])
.factory('hotels', function($http) {
var hotels = {};
hotels.get = function(callback) {
$http.get('/php/hotels.php?page='+$scope.page).success(function(data) {
callback(data);
});
};
return hotels;
});
angular.module('app', ['hotels', 'infinite-scroll'])
.controller('hotelsCtrl', function ($scope, hotels){
$scope.page = $scope.page + 1;
hotels.get({page: $scope.page}, function (data) {
$scope.hotels.push.apply($scope.hotels, data.results);
})
});
Any ideas?
This does the job:
angular.module('hotels', [])
.factory('hotels', function($http) {
var hotels = {};
hotels.get = function(params, callback) {
$http.get('/php/hotels.php', {params: {page: params.page}}).success(function(data) {
callback(data);
});
};
return hotels;
});
angular.module('app', ['hotels', 'infinite-scroll'])
.controller('hotelsCtrl', function ($scope, hotels){
$scope.page = 1;
$scope.addMoreItems = function() {
$scope.hotels=[];
hotels.get({page: $scope.page}, function (data) {
//$scope.hotels.push(data.results);
for (var i = 0; i < data.length; i++) {
$scope.hotels.push(data[i]);
}
$scope.page+=1;
})
}
});