Angular translate inside service - angularjs

I am struggling with angular translate for my ionic app. The thing is that I have a service with data to share between views but I need to translate this data. Unfortunately I just see blank screen without any errors in console.
I would appreciate if someone could help if there is something wrong with that code (I use useStaticFilesLoader):
app.service('customService', function($q, $rootScope, $filter, $translate) {
$rootScope.$on('$translateChangeSuccess', function () {
var $translate = $filter('translate');
return {
items: [
{
id: '1',
title:$translate('TITLE');
}
]
],
getItems: function() {
return this.items;
},
getItem: function(itemId) {
var dfd = $q.defer();
this.items.forEach(function(item) {
if (item.id === itemId) dfd.resolve(item);
});
return dfd.promise;
}
};
});
});

Try something like this:
app.factory('customService', function($rootScope, $translate) {
var items = [],
updateItems = function() {
items.length = 0;
$translate('TITLE').then(function(title) {
items.push({
id: '1',
title: title;
});
});
};
updateItems();
$rootScope.$on('$translateChangeSuccess', updateItems);
return {
items: items,
getItem: function(itemId) {
var result;
items.forEach(function(item) {
if (item.id === itemId) {
result = item;
}
});
return result;
}
}
});

Related

Delay loading data in Angular JS

I have code like this
(function (app) {
app.controller('productListController', productListController)
productListController.$inject = ['$scope', 'apiService', 'notificationService', '$ngBootbox', '$filter'];
function productListController($scope, apiService, notificationService, $ngBootbox, $filter) {
$scope.products = [];
$scope.page = 0;
$scope.pagesCount = 0;
$scope.getProducts = getProducts;
$scope.keyword = '';
$scope.search = search;
$scope.deleteProduct = deleteProduct;
$scope.selectAll = selectAll;
$scope.deleteMultiple = deleteMultiple;
function deleteMultiple() {
var listId = [];
$.each($scope.selected, function (i, item) {
listId.push(item.ID);
});
var config = {
params: {
checkedProducts: JSON.stringify(listId)
}
}
apiService.del('/api/product/deletemulti', config, function (result) {
notificationService.displaySuccess('Deleted successfully ' + result.data + 'record(s).');
search();
}, function (error) {
notificationService.displayError('Can not delete product.');
});
}
$scope.isAll = false;
function selectAll() {
if ($scope.isAll === false) {
angular.forEach($scope.products, function (item) {
item.checked = true;
});
$scope.isAll = true;
} else {
angular.forEach($scope.products, function (item) {
item.checked = false;
});
$scope.isAll = false;
}
}
$scope.$watch("products", function (n, o) {
var checked = $filter("filter")(n, { checked: true });
if (checked.length) {
$scope.selected = checked;
$('#btnDelete').removeAttr('disabled');
} else {
$('#btnDelete').attr('disabled', 'disabled');
}
}, true);
function deleteProduct(id) {
$ngBootbox.confirm('Are you sure to detele?').then(function () {
var config = {
params: {
id: id
}
}
apiService.del('/api/product/delete', config, function () {
notificationService.displaySuccess('The product hase been deleted successfully!');
search();
}, function () {
notificationService.displayError('Can not delete product');
})
});
}
function search() {
getProducts();
}
function getProducts(page) {
page = page || 0;
var config = {
params: {
keyword: $scope.keyword,
page: page,
pageSize: 20
}
}
apiService.get('/api/product/getall', config, function (result) {
if (result.data.TotalCount == 0) {
notificationService.displayWarning('Can not find any record.');
}
$scope.products = result.data.Items;
$scope.page = result.data.Page;
$scope.pagesCount = result.data.TotalPages;
$scope.totalCount = result.data.TotalCount;
}, function () {
console.log('Load product failed.');
});
}
$scope.getProducts();
}
})(angular.module('THTCMS.products'));
So my problem is when i loading data the application take me some time to load data.
I need load data as soon as
Is the any solution for this?
Since you are loading data via api call, there will be a delay. To handle this delay, you should display a loading screen. Once the data is loaded, the loading screen gets hidden and your main screen is visible. You can achieve this using $http interceptors.
See : Showing Spinner GIF during $http request in angular
The api-call is almost certainly causing the delay. Data may be received slowly via the api-call so you could display any sort of loading text/image to notify the use that the data is being loaded.
If u want the data ready at the time when controller inits, u can add a resolve param and pass the api call as a $promise in the route configuration for this route.

How do I unit test further .then and .catch branching in an Angular controller?

(function() {
'use strict';
angular
.module('walletInformation')
.controller('WalletInformationController', WalletInformationController);
/* #ngInject */
function WalletInformationController(
$q,
$scope,
config,
logger,
session,
$interpolate,
flowstack,
profileService,
walletInformationFormlyService,
postMsg
) {
// jshint validthis: true
var vm = this;
var app = $scope.app;
var user = session.get('profile').profile || {};
vm.saveWalletInformation = saveWalletInformation;
vm.onClickCancel = onClickCancel;
vm.deleteWallet = deleteWallet;
vm.model = {
walletInformation : {
firstName: user.name.first,
lastName: user.name.last,
emailAddress: user.emailAddress,
phoneNumber: user.mobilePhone.phoneNumber,
keepMeUpdated: user.preferences.receiveEmailNotification
}
};
activate();
////////////////
/**
* #function activate
* #description init function for the controller
* Calls paymentCard to get the
* */
function activate() {
createFormFields();
logger.info('Activated the Wallet Information View.');
}
function createFormFields() {
vm.fields = walletInformationFormlyService.getFormlyFields($scope.app.text);
}
function saveWalletInformation() {
var updatedProfile = createLegacyProfileInformation();
profileService.updateProfileInformation(updatedProfile).then(onSuccess).catch(onError);
function onSuccess(response) {
session.set('profile', {
profile: response.profile
});
if (vm.model.walletInformation.currentPassword && vm.model.walletInformation.newPassword) {
changePasswordRequest();
} else {
flowstack.add('accountManagement');
flowstack.next();
}
}
function onError(error) {
logger.error('Verify save Wallet Information Error: ', error);
}
//changePassword
function changePasswordRequest() {
var updatedPassword = {
data: {
currentPassword: vm.model.walletInformation.currentPassword,
newPassword: vm.model.walletInformation.newPassword
}
};
profileService
.changePassword(updatedPassword)
.then(onChangePasswordSuccess, onChangePasswordError);
function onChangePasswordSuccess(response) {
flowstack.add('accountManagement');
flowstack.next();
logger.info('Change password request: ', response);
}
function onChangePasswordError(response) {
logger.error('Change Password Error: ', response);
}
}
}
function deleteWallet() {
var appText = app.text.walletInformation;
console.log(appText);
flowstack.add('confirmation');
flowstack.next({
data: {
title: appText.deleteWalletConfirmationTitle,
body: appText.deleteWalletConfirmationBody,
cancelButton: appText.deleteWalletConfirmationCancelButton,
confirmButton: appText.deleteWalletConfirmationConfirmButton,
onConfirm: function() {
profileService.deleteWallet().then(deleteProfileSuccess, deleteProfileFailure);
function deleteProfileSuccess(response) {
if (response.profile) {
logger.info('profile is successfully deleted.', response);
postMsg.send('closeSwitch');
}
}
function deleteProfileFailure(error) {
logger.error('something went wrong while deleting profile.', error);
}
},
onCancel: function() {
flowstack.add('walletInformation');
flowstack.next();
}
}
});
}
function createLegacyProfileInformation() {
var updatedProfile = user;
var formlyField = vm.model.walletInformation;
//Update the profile
updatedProfile.name = {
first: formlyField.firstName,
last: formlyField.lastName
};
updatedProfile.mobilePhone.phoneNumber = formlyField.phoneNumber;
updatedProfile.preferences.receiveEmailNotification = formlyField.keepMeUpdated;
return {
data: updatedProfile
};
}
function onClickCancel() {
flowstack.back();
}
}
})();
Coverage is saying that onSuccess of saveWalletInformation and changePasswordRequest isnt't covered but I'm not sure exactly how to test it, the only thing I've tested now is that the saveWalletInformation function is calling the profile service:
describe.only('WalletInformationController ---', function() {
var controller, scope;
var userProfile = {
profile: {
name: {
first: 'someonefirstname',
last: 'someoneslastname'
},
emailAddress: 'someone#something.com',
mobilePhone: {
countryCode: 'US+1',
phoneNumber: '123 212 2342'
},
preferences: {
receiveEmailNotification: true
}
}
};
beforeEach(function() {
bard.appModule('walletInformation');
bard.inject(
'$q',
'$controller',
'$rootScope',
'api',
'flowstack',
'logger',
'session',
'profileService'
);
session.set('profile', userProfile);
});
beforeEach(function() {
sandbox = sinon.sandbox.create();
scope = $rootScope.$new();
scope.app = {
text: {
global: {},
walletInformation: {
deleteWalletConfirmationTitle: 'Confirm Wallet Deletion?'
},
userInformation: {
emailValidation: 'Please enter valid email'
},
signin: {
rememberMeLabel: 'remember me'
}
}
};
controller = $controller('WalletInformationController', {
$scope: scope
});
loggerErrorStub = sandbox.stub(logger, 'error');
sandbox.stub(logger, 'info');
controller = $controller('WalletInformationController', {
$scope: scope
});
});
describe('saveWalletInformation method', function() {
beforeEach(function() {
// apiStub.restore();
sandbox.stub(profileService, 'updateProfileInformation', function() {
return $q.when(userProfile);
});
});
it('should saveWalletInformation successfully', function() {
controller.saveWalletInformation();
expect(profileService.updateProfileInformation).to.have.been.called;
});
it('should log error msg when saveWalletInformation call fails', function() {
profileService.updateProfileInformation.restore();
sandbox.stub(profileService, 'updateProfileInformation', function() {
return $q.reject();
});
controller.saveWalletInformation();
scope.$apply();
expect(loggerErrorStub).to.have.been.calledOnce;
});
it('should call changePasswordRequest when currentPassword and newPassword are set', function() {
sandbox.stub(profileService, 'changePassword', function() {
return $q.when({
success: true,
extensionPoint: null
});
});
sandbox.stub(flowstack, 'add');
sandbox.stub(flowstack, 'next');
controller.saveWalletInformation();
// scope.$apply();
// expect(flowstack.next).to.have.been.calledOnce;
// expect(flowstack.add).to.have.been.calledOnce;
expect(profileService.updateProfileInformation).to.have.been.called;
// expect(profileService.changePassword).to.have.been.called;
});
});
You can let the service call go a step further and instead of verifying that service function was called, as you do here:
expect(profileService.updateProfileInformation).to.have.been.called;
You can instead mock the response from the api call with $httpBackend:
httpBackend.expectGET('your/url/here').respond(200, {response object...});
or
httpBackend.expectGET('your/url/here').respond(500, {error object...});
Then you'll be hitting both the error and success functions when your tests run

angular $resource methods dont send the right value

this is my service
.factory('ProductData', ['$resource', function($resource) {
return $resource('product/:id', {id: '#id'}, {
'update': { method:'PUT' },
'insertNew': { method:'POST' },
'delete': { method:'DELETE' },
});
}]);
and this is in my conroller
$scope.updateProduct = function(item) {
var product = ProductData.get({
id : item.id
}, function() {
product.name = item.name;
product.description = item.description;
product.ctg_id = item.ctg_id;
product.ctgid = item.ctg_id;
product.$update(item.id);
});
};
$scope.deleteProduct = function(item) {
var product = ProductData.get({
id : item.id
}, function() {
product.id = item.id;
product.$delete(item.id);
});
};
when I was working in WAMP, all methods worked fine.
but when I uploaded to a webserver,
GET request sends the right value example:
http://www.xxx-xxx.com/product/53
but all other methods send this
http://www.xxx-xxx.com/product/53?0=5&1=3
how can I fix this?
You should call: ProductData.delete(...) in the $scope.deleteProduct function

angular, try to display object in ng-repeat fails

i'm writing an mobile application in javascript with angularJS and ionicframework (last beta v.11), i create dinamically an object and want to display all objects inside in a ng-repeat. Why nr-repeat don't display anything?
This is screen from my object:
I use this code for put values in scope:
$scope.distanceSuppliers = myCar;
And this is the code in html:
<ion-item ng-repeat="(id, supplier) in distanceSuppliers">
<div class="items item-button-right" ng-click="openDetails(id)">
{{supplier.name}}<br />
{{supplier.address}}<br />
</div>
</ion-item>
This is my complete code for JS:
.controller('suppliers', function($scope, cw_db, $ionicPopup, $ionicActionSheet, appdelegate, $rootScope, $firebase, $location, $ionicLoading, cw_position) {
$ionicLoading.show({
template: 'Updating data..'
});
var geocoder;
var tot = 0;
var done = 0;
geocoder = new google.maps.Geocoder();
cw_db.getData(cw_db.getSuppliers(), "", function(suppliers) {
cw_position.getPosition(function (error, position) {
suppliers.on('value', function(supp) {
$scope.distanceSuppliers = {};
tot = 0;
done = 0;
supp.forEach(function(childSnapshot) {
tot++;
var childData = childSnapshot.val();
if (childData.address) {
calculateDistance(childData, position.coords.latitude, position.coords.longitude);
}
});
});
$ionicLoading.hide();
});
});
function calculateDistance(childData, usrLat, usrLon) {
var service = new google.maps.DistanceMatrixService();
service.getDistanceMatrix(
{
origins: [new google.maps.LatLng(usrLat, usrLon)],
destinations: [childData.address],
travelMode: google.maps.TravelMode.DRIVING,
unitSystem: google.maps.UnitSystem.METRIC,
avoidHighways: false,
avoidTolls: false
}, function(response, status) {
if (status != google.maps.DistanceMatrixStatus.OK) {
alert('Error was: ' + status);
} else {
done++;
var results = response.rows[0].elements;
childData.distance = results[0].distance.value;
$scope.distanceSuppliers.push(childData);
if (done == tot) {
console.log($scope.distanceSuppliers);
}
}
});
}
$scope.openDetails = function(index) {
//appdelegate.setCallId(index);
//$location.path("/app/supplierDetails");
}
})
what's wrong?
Not sure, but I believe you have a data binding update problem.
Try using the $timeout to force the render:
w_position.getPosition(function (error, position) {
$timeout(function() {
suppliers.on('value', function(supp) {
$scope.distanceSuppliers = {};
tot = 0;
done = 0;
supp.forEach(function(childSnapshot) {
tot++;
var childData = childSnapshot.val();
if (childData.address) {
calculateDistance(childData, position.coords.latitude, position.coords.longitude);
}
});
});
$ionicLoading.hide();
});
});
And don't forget to add the $timeout parameter to the controller:
.controller('suppliers', function($scope, ...<other parameters here>..., $timeout) {
I found the problem! Fix using $scope.$apply();
The problem was that i was writing in a different $scope using this code:
cw_position.getPosition(function (error, position) {
suppliers.on('value', function(supp) {
tot = 0;
done = 0;
supp.forEach(function(childSnapshot) {
tot++;
var childData = childSnapshot.val();
if (childData.address) {
calculateDistance(childData, position.coords.latitude, position.coords.longitude);
}
});
});
$ionicLoading.hide();
});
where cw_position.getPosition call a js with this code:
angular.module('cw_position', [])
.service('cw_position', function() {
this.getPosition = function(callback) {
navigator.geolocation.getCurrentPosition(
function (position) {
return callback(null, position);
},
function(error) {
return callback(error, null);
}
);
}
// Built google maps map option
//
this.getGoogleMapOptions = function (lat, lon, zoom, type) {
if (type == null) {
type = google.maps.MapTypeId.ROADMAP;
}
var mapOptions = {
center: new google.maps.LatLng(lat, lon),
zoom: zoom,
mapTypeId: type
};
return mapOptions;
}
});
navigator.geolocation.getCurrentPosition causes the 'problem'
Thx to all for your help

How to manually add a datasource to Angularjs-select2 when select2 is set up as <input/> to load remote data?

I am using the Select2 as a typeahead control. The code below works very well when the user types in the search term.
However, when loading data into the page, I need to be able to manually set the value of the search box.
Ideally something like: $scope.selectedProducerId = {id:1, text:"Existing producer}
However, since no data has been retrieved the Select2 data source is empty.
So what I really need to be able to do is to add a new array of data to the datasource and then set the $scope.selectedProducerId, something like: $scope.producersLookupsSelectOptions.addNewData({id:1, text:"Existing producer}) and then
$scope.selectedProducerId = 1;
Researching this I have seen various suggestions to use initSelection(), but I can't see how to get this to work.
I have also tried to set createSearchChoice(term), but the term is not appearing in the input box.
I would be most grateful for any assistance.
Thanks
This is the html
<div class="col-sm-4">
<input type="text" ui-select2="producersLookupsSelectOptions" ng- model="selectedProducerId" class="form-control" placeholder="[Produtor]" ng-change="selectedProducerIdChanged()"/>
</div>
This is the controller
angular.module("home").controller("TestLookupsCtrl", [
"$scope", "$routeParams", "AddressBookService",
function($scope, $routeParams, AddressBookService) {
$scope.producersLookupsSelectOptions = AddressBookService.producersLookupsSelectOptions();
}
]);
This is the service:
angular.module("addressBook").service("AddressBookService", [
"$http", "$q", function($http, $q) {
var routePrefix = "/api/apiAddressBook/";
//var fetchProducers = function(queryParams) {
// return $http.get(routePrefix + "GetClientsLookup/" + queryParams.data.query).then(queryParams.success);
//};
var _getSelectLookupOptions = function(url, minimumInputLength, idField, textField) {
var _dataSource = [];
var _queryParams;
return {
allowClear: true,
minimumInputLength: minimumInputLength || 3,
ajax: {
data: function(term, page) {
return {
query: term
};
},
quietMillis: 500,
transport: function(queryParams) {
_queryParams = queryParams;
return $http.get(url + queryParams.data.query).success(queryParams.success);
},
results: function(data, page) {
var firstItem = data[0];
if (firstItem) {
if (!firstItem[idField]) {
throw "[id] " + idField + " does not exist in datasource";
}
if (!firstItem[textField]) {
throw "[text] " + textField + " field does not exist in datasource";
}
}
var arr = [];
_.each(data, function(returnedData) {
arr.push({
id: returnedData[idField],
text: returnedData[textField],
data: returnedData
});
});
_dataSource = arr;
return { results: arr };
}
},
dataSource: function() {
return _dataSource;
},
getText: function (id) {
if (_dataSource.length === 0) {
throw ("AddressBookService.getText(): Since the control was not automatically loaded the dataSource has no content");
}
return _.find(_dataSource, { id: id }).text;
}
//initSelection: function(element, callback) {
// callback($(element).data('$ngModelController').$modelValue);
//},
//createSearchChoice:function(term) {
// return term;
//},
addNewData:function(data) {
this.ajax.results(data,1);
};
};
return {
producersLookupsSelectOptions: function() {
var url = routePrefix + "GetClientsLookup/";
return _getSelectLookupOptions(url, 2, "Id", "Name");
},
}
}
]);

Resources