stateparms are attached with current state - angularjs

when I pass the stateParams to another state, they concatenate with the state and getting following results in my IONIC App.
var $currState = $ionicHistory.currentView().stateId;
$scope.consoleLog('$currState: ' + $currState); //$currState: app.stateA_purchaseData=[object Object]_supplierData=[object Object]"
$scope.consoleLog('$stateParams: ' + JSON.stringify($stateParams)); //$stateParams: {}
and here is the config
state('app.StateA', {
url: '/test-url',
templateUrl: 'templates/test.html',
controller: 'AppCtrl',
cache: false,
params: {
purchaseData: null,
supplierData: null,
}
})
$state.go('app.StateA', {purchaseData: $scope.purchaseData, supplierData: $scope.supplierData });

This is happening because, in the documentation of Ionic history there is a method getCurrentStateId() which concatenates the statename with params.
Check from line no 142 in ionic_history.js in github documentation
function getCurrentStateId() {
var id;
if ($state && $state.current && $state.current.name) {
id = $state.current.name;
if ($state.params) {
for (var key in $state.params) {
if ($state.params.hasOwnProperty(key) && $state.params[key]) {
id += "_" + key + "=" + $state.params[key];
}
}
}
return id;
}
// if something goes wrong make sure its got a unique stateId
return ionic.Utils.nextUid();
}
To get the parameters instead,
try,
StateParams() which calls getCurrentStateParams()
function getCurrentStateParams() {
var rtn;
if ($state && $state.params) {
for (var key in $state.params) {
if ($state.params.hasOwnProperty(key)) {
rtn = rtn || {};
rtn[key] = $state.params[key];
}
}
}
return rtn;
}
This actually return params object for you.
Reference(source) of the above functions

Related

The first argument of the `$location#search()` call must be a string or an object

Im working on an angularjs and MVC app, my app works fine but im getting an error in my console.
Error: $location:isrcharg
Wrong $location.search() argument type
The first argument of the $location#search() call must be a string or an object
this is my angularjs navigation service:
self.goBack = function () {
$window.history.back();
}
self.navigateTo = function (path, params) {
if (params === null) {
$location.path(MyApp.rootPath + path);
}
else {
$location.path(MyApp.rootPath + path).search(params);
}
};
self.refreshPage = function (path) {
$window.location.href = MyApp.rootPath + path;
};
self.clone = function (obj) {
return JSON.parse(JSON.stringify(obj))
};
self.querystring = function (param) {
if ($location.search !== null)
return $location.search()[param];
else
return null;
};
self.resetQueryParams = function () {
$location.url($location.path());
};
return this;
};
this above code is a common factory, so after injecting it to my controler thats how i navigate
inside angular i use viewModelHelper.navigateTo("/home");
then if i want to navigate to mvc page i use
viewModelHelper.refreshPage("index");
im getting error in this code when im navigationTo
$location.path(MyApp.rootPath + path).search(params);
my params is not defined. How do i solve this undefined problem
self.navigateTo = function (path, params) {
if ( ̶p̶a̶r̶a̶m̶s̶ ̶=̶=̶=̶ ̶n̶u̶l̶l̶ !params) {
$location.path(MyApp.rootPath + path);
}
else {
$location.path(MyApp.rootPath + path).search(params);
}
};
OR
self.navigateTo = function (path, params) {
if (params) {
$location.path(MyApp.rootPath + path).search(params);
}
else {
$location.path(MyApp.rootPath + path);
}
};
In the above example, the code will only execute the .search method if the params variable is truthy.
In JavaScript, a truthy value is a value that is considered true when evaluated in a Boolean context. All values are truthy unless they are defined as falsy (i.e., except for false, 0, "", null, undefined, and NaN).
For more information, see MDN JavaScript Reference - truthy

Validate a textbox input with an array list in angularjs

I am very new to AngularJS and currently I am working on a form which is designed in angularjs.
My task is to validate a textbox input with a list. If the value entered in textbox is not present in the list then it should throw a validation error.
I have written the below lines of code for getting the list items through rest API:
app.factory("EatonScanningFactory", ['$http', function($http) {
var EatonScanningFactoryObj = {};
EatonScanningFactoryObj.GetToolMaxTimeList = function (columnName) {
return $http({
method: 'GET',
url: _spPageContextInfo.webAbsoluteUrl
+ "/_api/web/lists/getbytitle('Tool%20Max%20Time')/Items/"
+ "?$select=Text,Value&$orderby=Text&$filter=Title eq '" + columnName + "'",
headers: { "Accept": "application/json;odata=verbose" }
});
}
It will return the list items into an array.
The below lines of code are for accessing calling the above function:
var getToolId = EatonScanningFactory.GetToolMaxTimeList('ToolNumber');
var getMaxLife = EatonScanningFactory.GetToolMaxTimeList('MaxLife');
I am unable to proceed further as I am not sure how to validate if my text box input is available in the list or not.
Please help
Hi there here is a plausible solution as an example:
$scope.list = EatonScanningFactory.GetToolMaxTimeList('MaxLife');
Javascript (Native) Example:
function validateList() {
var IsInList = false;
for (var i = 0; i < $scope.list.length; i++) {
if ($("#textbox").val() == $scope.list[i].listvalue) {
IsInList = true;
break;
}
}
return IsInList;
}
Angular Example:
$scope.validateFunction = function() {
angular.forEach($scope.list, function(value, key){
var IsInList = false;
if($("#textbox").val() == value.listvalue) {
IsInList = true;
break;
}
});
return IsInList;
}
//Invoke the function like follow:
$scope.validateFunction();

Switch between 2 ng-shows

I have two elements with a ng-show in them,
%a.follow{"ng-click" => "followUser(user)", "ng-show" => "!isFollowed(user.id)"} follow
%a.unfollow{"ng-click" => "unfollowUser(user)", "ng-show" => "isFollowed(user.id)"} unfollow
It depends on the user.id which ng-show is being rendered in the template. So only one of the two ng-shows is displayed.
So for example a user wants to start following another user. Then the follow link is displayed.
%a.follow{"ng-click" => "followUser(user)", "ng-show" => "!isFollowed(user.id)"} follow
When a user clicks on it, I would like to hide the clicked ng-show, and show the unfollow ng-show so that the user can unfollow the just followed user.
The follow and unfollow user function,
$scope.followUser = function (user) {
followUser.create({
followed_id: user.id
}).then(init);
Notification.success(user.name + ' is toegevoegd als vriend.');
}
$scope.unfollowUser = function(user){
unfollowUser.unfollowUser(user).then(function(){
},function(){
}).then(init);
Notification.success(user.name + ' is verwijderd als vriend.');
}
And the isFollowed function,
usersService.loadUsers().then(function(response) {
$scope.users = response.data;
console.log ($scope.users)
angular.forEach(response, function(user){
$scope.user = user
$scope.isFollowed = function(userId) {
var following = $scope.current_user.following;
for (var i=0; i<following.length; i++) {
if (following[i].id == userId) {
return true;
}
}
return false;
}
})
})
I've tried building this,
<a ng-click="follow=false ;unfollow=true", ng-show="follow">Follow!</a>
<a ng-click="follow=true; unfollow=false", ng-show="unfollow">Unfollow!</a>
This does switch between the two ng-shows, but when I try to get the isFollowed(user.id), !isFollowed(user.id) in them the code crashes.
You should create single function to follow/unfollow, Here in the code snippet I have introduced a new property i.e. isFollowed to object user whose value is set using the isFollowed function.
Additionally, Don't overuse isFollowed(user.id) method, it will be huge performance hit.
HTML
<a ng-click="followUnfollowUser(user)"> {{ user.isFollowed : "Unfollow!" : "Follow!"}} </a>
Script
$scope.followUnfollowUser = function(user) {
//If followed - unfollow
if (user.isFollowed) {
unfollowUser.unfollowUser(user).then(function() {
user.isFollowed=!user.isFollowed
}, function() {
}).then(init);
Notification.success(user.name + ' is verwijderd als vriend.');
} else {
followUser.create({
followed_id: user.id
}).then(function() {
user.isFollowed=!user.isFollowed
}, function() {
}).then(init);
Notification.success(user.name + ' is toegevoegd als vriend.');
}
}
//Define method to check wheather current user is beign followed
var isFollowed = function(userId) {
var following = $scope.current_user.following;
for (var i = 0; i < following.length; i++) {
if (following[i].id == userId) {
return true;
}
}
return false;
}
//Fetch Users
usersService.loadUsers().then(function(response) {
$scope.users = response.data;
//Iterate and create isFollowed property
angular.forEach($scope.users, function(user) {
user.isFollowed = isFollowed(user.id);
})
})
Note: I'm not familiar with following syntax thus used standard HTML.
%a.follow{"ng-click" => "followUser(user)", "ng-show" => "!isFollowed(user.id)"} follow
Alrhgout Satpal did point me to the right direction and helped me with some code. His answer isn't complete. So I've decided that add the code I'm using for this function (made with the help of Satpal!).
I've created a followUnfollowUser function. But instead of having two .then(init) I have one init() at the end of the function. Having the two inits gave me some looping trouble.
$scope.followUnfollowUser = function(user) {
//If followed - unfollow
if (user.isFollowed) {
unfollowUser.unfollowUser(user).then(function() {
user.isFollowed=!user.isFollowed
}, function() {
})
Notification.success(user.name + ' is verwijderd als vriend.');
} else {
followUser.create({
followed_id: user.id
}).then(function() {
user.isFollowed=!user.isFollowed
}, function() {
})
Notification.success(user.name + ' is toegevoegd als vriend.');
}
init();
}
Then the init function,
var init = function () {
loadCurrent_user.loadCurrent_user().then(function(response) {
$scope.current_user = response.data;
});
usersService.loadUsers().then(function(response) {
$scope.users = response.data;
//Iterate and create isFollowed property
angular.forEach($scope.users, function(user) {
user.isFollowed = isFollowed(user.id);
})
})
var isFollowed = function(userId) {
var following = $scope.current_user.following;
for (var i = 0; i < following.length; i++) {
if (following[i].id == userId) {
return true;
}
}
return false;
}
}
First I load the current user so that the $scope.current_user gets updated when a user is being followed/unfollowed. And then I iterate through each user and create the isFollowed value using the isFollowed function.
And in my template I have,
%a{"ng-click" => "followUnfollowUser(user)"}
-# {{ user.isFollowed }}
{{ user.isFollowed ? "Unfollow user" : "Follow user"}}

Prevent multiple submits in angularjs

I'm looking for a AngularJS-based way to prevent multiple submits per task.
I don't need buttons to be disabled after submission or close the form and wait for the task to be completed. Instead, I need requests to be unique.
To be more detailed, I need $http.get and $http.post stop sending multiple same requests.
Any Ideas?
According to this article, you can use provider decorator.
NOTE: this approach is based on angular-api
https://gist.github.com/adambuczynski/354364e2a58786e2be71
UPDATE
I've changed a little part in your suggested solution, because returned promises have lost .success and .error and .then.
Just use this edited code to have all of those functions working:
.config(["$provide", function ($provide) {
$provide.decorator('$http', function ($delegate, $q) {
var pendingRequests = {};
var $http = $delegate;
function hash(str) {
var h = 0;
var strlen = str.length;
if (strlen === 0) {
return h;
}
for (var i = 0, n; i < strlen; ++i) {
n = str.charCodeAt(i);
h = ((h << 5) - h) + n;
h = h & h;
}
return h >>> 0;
}
function getRequestIdentifier(config) {
var str = config.method + config.url;
if (config.data && typeof config.data === 'object') {
str += angular.toJson(config.data);
}
return hash(str);
}
var $duplicateRequestsFilter = function (config) {
if (config.ignoreDuplicateRequest) {
return $http(config);
}
var identifier = getRequestIdentifier(config);
if (pendingRequests[identifier]) {
if (config.rejectDuplicateRequest) {
return $q.reject({
data: '',
headers: {},
status: config.rejectDuplicateStatusCode || 400,
config: config
});
}
return pendingRequests[identifier];
}
pendingRequests[identifier] = $http(config);
$http(config).finally(function () {
delete pendingRequests[identifier];
});
return pendingRequests[identifier];
};
Object.keys($http).filter(function (key) {
return (typeof $http[key] === 'function');
}).forEach(function (key) {
$duplicateRequestsFilter[key] = $http[key];
});
return $duplicateRequestsFilter;
})
}])
It could be a performance issue but following idea could solve your problem.
Store the each request URL and DATA as key value pair on a variable. URL should be KEY. For Same URL multiple submission can be stored in a Array.
Then for any new call check the URL if it present in your stored object, then compare the data with each object thorughly (deep check, it is costly though).
If any exact match found then stop the processing. As same request came.
Other wise proceed and don't forget to store this data also.
But it is costly since need to check the data which could be havy.
Note: At the time of storing the data you could convert it to JSON String so it will be easier to compare between String.
here is the Code Algo
YourService.call(url, params) {
var Str1 = JSON.stringify(params);
if(StoredObj[url]) {
for each (StoredObj[url] as Str){
if(Str === Str1) {
return;
}
}
}
else {
StoredObj[url] = []; //new Array
}
StoredObj[url].push(Str1);
Call $http then;
}

angularjs Ionic and global variables: best practice to make a variable available globally

I am new to Angular/Ionic.
Before using Angular/Ionic, at the launch of my app, I was checking if we were under Phonegap or a browser using and storing this information in a global boolean variable and then checking if the app was online or offline and storing it to a global variable too, like this :
var isPhoneGap;
var connectionStatus;
isPhoneGap = checkIfPhoneGap();
//later in the code :
connectionStatus = checkIfOnline();
function checkIfPhoneGap() {
var app = document.URL.indexOf( 'http://' ) === -1 && document.URL.indexOf( 'https://' ) === -1; // && document.URL.indexOf( 'file://' );
if ( app ) {
return true;
} else {
return false;
}
}
function checkIfOnline() {
if ( isPhoneGap ) {
if (checkConnection() == "none" ) {
connectionStatus = 'offline';
} else {
connectionStatus = 'online';
}
function checkConnection() {
var networkState = navigator.network.connection.type;
var states = {};
states[Connection.UNKNOWN] = 'Unknown connection';
states[Connection.ETHERNET] = 'Ethernet connection';
states[Connection.WIFI] = 'WiFi connection';
states[Connection.CELL_2G] = 'Cell 2G connection';
states[Connection.CELL_3G] = 'Cell 3G connection';
states[Connection.CELL_4G] = 'Cell 4G connection';
states[Connection.NONE] = 'No network connection';
//console.log('Connection : ' + Connection);
//console.log('Connection type: ' + states[networkState]);
return networkState;
}
} else {
connectionStatus = navigator.onLine ? 'online' : 'offline';
}
return connectionStatus;
}
Now I would like to do the same with Angular/Ionic, I understand that I have to use a "Service". But is it the best way to make this information available through all the code ?
I am doing the following, but is it the "best practice" ?
in index.html :
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/services.js"></script>
in services.js :
angular.module('SnowBoard.services', [])
.factory('isPhoneGap', function() {
var appp = document.URL.indexOf( 'http://' ) === -1 && document.URL.indexOf( 'https://' ) === -1; // && document.URL.indexOf( 'file://' );
if ( appp ) {
return true;
} else {
return false;
}
})
;
in app.js :
angular.module('SnowBoard', ['ionic', 'SnowBoard.controllers', 'SnowBoard.services'])
.run(["isPhoneGap","$ionicPlatform", function(isPhoneGap, $ionicPlatform) {
$ionicPlatform.ready(function() {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if(window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if(window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.styleDefault();
}
});
//CHECK IF ONLINE
connectionStatus = checkIfOnline(isPhoneGap);
//DEBUG
//var debugOptionUseLocalDB=0;
//updateProDB(connectionStatus, debugOptionUseLocalDB);
}])
.config(function($stateProvider, $urlRouterProvider) {
//...all state configurations
})
.config(function($stateProvider, $urlRouterProvider) {
//...
});
This works for now, but I need the boolean isPhoneGap to be available everywhere I need it (almost everywhere in my app).
Can you converge to the best practice to do this ?
Thanks
You should not set variables using $rootScope, and try to refrain from using $scope as much as possible. Using LocalStorage is okay, but this data will persist. I would recommend setting up a factory to store and retrieve variables using SessionStorage. SessionStorage is tied to the tab you have open, so the data is gone when it is closed.
This is one of my session storage services. I throw $cookieStorage in case local storage isn't available. Also, localStorage can only store strings. This is why you will see me converting objects and arrays to and from JSON as needed. After injecting sessionService, I need only call sessionService.store(name, data) to store a session variable or sessionService.persist(name, data) to store persistent data i.e. userName if "Remember Me" is checked. :
.service('sessionService', ['$cookieStore', function ($cookieStore) {
var localStoreAvailable = typeof (Storage) !== "undefined";
this.store = function (name, details) {
if (localStoreAvailable) {
if (angular.isUndefined(details)) {
details = null;
} else if (angular.isObject(details) || angular.isArray(details) || angular.isNumber(+details || details)) {
details = angular.toJson(details);
};
sessionStorage.setItem(name, details);
} else {
$cookieStore.put(name, details);
};
};
this.persist = function(name, details) {
if (localStoreAvailable) {
if (angular.isUndefined(details)) {
details = null;
} else if (angular.isObject(details) || angular.isArray(details) || angular.isNumber(+details || details)) {
details = angular.toJson(details);
};
localStorage.setItem(name, details);
} else {
$cookieStore.put(name, details);
}
};
this.get = function (name) {
if (localStoreAvailable) {
return getItem(name);
} else {
return $cookieStore.get(name);
}
};
this.destroy = function (name) {
if (localStoreAvailable) {
localStorage.removeItem(name);
sessionStorage.removeItem(name);
} else {
$cookieStore.remove(name);
};
};
var getItem = function (name) {
var data;
var localData = localStorage.getItem(name);
var sessionData = sessionStorage.getItem(name);
if (sessionData) {
data = sessionData;
} else if (localData) {
data = localData;
} else {
return null;
}
if (data === '[object Object]') { return null; };
if (!data.length || data === 'null') { return null; };
if (data.charAt(0) === "{" || data.charAt(0) === "[" || angular.isNumber(data)) {
return angular.fromJson(data);
};
return data;
};
return this;
}])
$cookieStore is part of ngCookies. Make sure you have angular-cookies.js included and load ngCookies as you would any module. Angular ngCookies
First off, I'm pretty new to both Ionic and Angular, however I had the same problem with my web app Angular and I have done following to get it working
assign variables to $rootScope, that way it's visible to all the controllers
assign variables to $scope , which is visible by current context. Ex: controller and the html pages uses that controller
localStorageService, because this will hold the values even after user refreshes the page.
Again please note, this is what I did in my Angular web app and might not be the best practices, but I hope you get the idea.
There are methods available in ionic.Platform that assist in getting back the data you need in regards to the device type.
http://ionicframework.com/docs/api/utility/ionic.Platform/
You could alternatively look at adding ngCordova, which has a bunch of useful wrappers around cordova plugins, including the device plugin.
http://ngcordova.com/docs/#Device

Resources