Parse.initialize breaking Angular Cordova app in iOS simulation - angularjs

So I have an app in angular with cordova, that works as expected when served to a local web host, pushing and pulling the login data from parse.com.
But, when I compile and emulate in an IOS emulator, it appears that the command
parse.initialize("453ioejblahgf3oi5j35p","f30903959fblahblah");
is making $state.go fail to work.
:(
Upon closer inspection, it seems as though Parse.initialize("faerfaerfaerf";"aefaerfeafaer"); is putting a stop to all code that comes after it --
$scope.registerNowClick = function (user) {
//Copy the user to $scope.tmpUser
$scope.tmpUser = angular.copy(user);
// PARSE INITILIZATION CALL Parse.initialize("Zmqvefjaeifai34jofewOvRDxfNdoxH", "HlzTePUSi3fja305f0j341");
alert('Register Now was clicked w/ Email:' + $scope.tmpUser.email);
// PARSE ADD A USER
var user = new Parse.User();
user.se blah blah
If I move the alert above the parse.init, it fires. But when it's after the parse.init, it doesn't.

Javascript is interpreted language. Meaning that, any run-time errors wont halt the program, until that particular line is reached.
Looking at your problem, it looks like Object Parse is not defined. Have you included any parse.js files that it may require? Move Parse.initialize() to the end of the script so that it wont halt the rest of the code from executing.

I have put my Parse initialization in a separate UserService.init() that must be resolved at app startup.
.state('tab', {
url: "/tab",
abstract: true,
templateUrl: "templates/tabs.html",
resolve: {
user: function (UserService) {
var value = UserService.init();
// alert(value); // for debugging
return value;
}
}
})
Here is a snippet of the UserService code
init: function () {
var value = null;
var deferred = $q.defer();
// if initialized, then return the activeUser
if (parseInitialized === false) {
Parse.initialize(ParseConfiguration.applicationId, ParseConfiguration.javascriptKey);
parseInitialized = true;
console.log("parse initialized in init function");
}
setTimeout(function () {
var currentUser = Parse.User.current();
if (currentUser) {
deferred.resolve(currentUser);
} else {
deferred.reject({error: "noUser"});
}
}, 100);
return deferred.promise;
},
The complete solution is here ... https://github.com/aaronksaunders/dcww

Related

Why can't I get a new function in an AngularJS provider to run?

I have a django application using AngularJS on the front end.
I have added a function to an AngularJS provider (getByEmployeeId).
app.provider('changeTrackingService', function( CTO_LOCAL_STORAGE_BYTES, MEGABYTE_MULTIPLIER, LOGGED_IN_EMPLOYEE) {
this.getByEmployeeId = function (employee_id) {
return httpServ.post('/hr/get_ctm_by_employee', {employee_id: employee_id}).then(function (resp) {
return objectModel(resp.data.object_id, resp.data.changeset);
});
}
this.getByEncounterId = function (encounter_id) {
return httpServ.post('/encounters/get_ctm_by_encounter', {encounter_id: encounter_id}).then(function (resp) {
return objectModel(resp.data.object_id, resp.data.changeset);
});
}
this.$get = function ($http) {
httpServ = $http;
return {
getByEmployeeId: this.getByEmployeeId,
getByEncounterId: this.getByEncounterId,
getByOrderId: this.getByOrderId
}
}
When I try to run that provider function from a function int he service, nothing happens. The existing function, getByEncounterId works completely fine. But, getByEmployeeId does absolutely nothing. No errors... everything just stops right then.
app.service('chartProvider', ['$http', 'changeTrackingService', function($http, changeTrackingService){
return {
get: function(entity_id, isEmployee = false) {
if(isEmployee)
return changeTrackingService.getByEmployeeId(entity_id).then(function (object) {
return object;
});
else
return changeTrackingService.getByEncounterId(entity_id).then(function (object) {
return object;
});
},
If I look at the changeTrackingService while debugging, this it is showing the function is there.
{getByEmployeeId: ƒ, getByEncounterId: ƒ, getByOrderId: ƒ}
If I look at the .js file in the browser, the function is there.
If I change it to incorrectly run getByEncounterId it works fine.
I have tried clearing caches, rebuilding docker images, re-collecting static files and spinning around in my chair three times while cutting a potato in half.

calling controller function from within a promise in external JS

Ionic Tabs, root of tabs HTML has "RootTabCtrl", and "Tab1" (with "Tab1_Ctrl") has a form, other tabs are disabled.
User submits form on Tab1
Tab1 Controller function kicks off.
Controller Function calls an external function (not in controller).
External function triggers, which executes a promise
In promise "results", returned data is processed
If X in returned data is true, trigger "RootTabCtrl" function to enable the other disabled tabs.
I can track console messages triggering every step of the way.
This all works except for this following odd behavior. "RootTabCtrl" doesn't enable the disabled tabs until the user clicks the form submit a second time...even though I see console messages saying it is in (at the end) of the RootTabCtrl function. I see all the same console messages from the first click - but on the 2nd time is when the disabled tabs get enabled again.
If I move step 6 outside of the promise in Step 4, and put it after step 3 (and before the promise), then all the tabs get enabled on the 1st click. However, this is no longer taking into account the value of X to determine if other tabs should be re-enabled or not.
What can I look for, or am not aware of, that would be causing this?
app.js:
.state('tab', {
url: "/tab",
abstract: true,
templateUrl: "templates/tabs.html",
controller: 'TabsCtrl'
})
// Each tab has its own nav history stack:
.state('tab.tab1', {
url: '/map',
views: {
'tab-1': {
templateUrl: 'templates/tab-1.html',
controller: 'tab1Ctrl'
}
}
})
controllers:
.controller('TabsCtrl', function($scope,$rootScope,constants) {
$scope.constants = constants ;
$scope.tabControl = {
disableRides : true,
disableBikes : true,
disableTransit : true
}
var refreshFinalizer = $rootScope.$on('updateTabsRefresh', function (event, data) {
console.log("Refresher 1") ;
$scope.tabControl.disableTab2 = false;
$scope.tabControl.disableTab3 = false ;
console.log("Refresher 2") ;
});
$scope.$on('$destroy', function () {
console.log("Destroy") ;
refreshFinalizer ();
});
})
.controller('tab1Ctrl', function($scope,$rootScope) {
$scope.setInfo= function() {
getGoogle(document.getElementById('form_data').value,0);
}
$scope.enableTabs = function(type) {
console.log("Here enableTabs1") ;
$rootScope.$broadcast('updateTabsRefresh');
console.log("Here enableTabs2") ;
}
})
Tab1 has a form, upon click, it executes $scope.setInfo. Then getGoogle() is in an outside JS function, its a call to google maps, and if specific data X is true, then enable all the other tabs using tab1Ctrl $scope.enableTabs() :
function getGoogle(userInfo,clear) {
console.log("setInfo 1") ;
geoCoder.geocode({'address': userInfo}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[0]) {
// extra code removed
startPointSet = 1;
// tab1Ctrl html has id of "Tab1"
angular.element(document.getElementById('Tab1')).scope().enableTabs();
/* alternative method, worked the same as previous line but with same problem
var $sBody = angular.element(document.body) ;
var $sRootScope = $sBody.injector().get('$rootScope') ;
$sRootScope.$broadcast('updateTabsRefresh') ;
*/
console.log("setInfo 2") ;
}
} else {
// extra code removed
console.log(response) ;
}
});
}
}
All of the above works...except that when the call to enableTabs (within the google response), even though it correctly calls enableTabs and I can see the console.log messages firing from within enableTabs - the other tabs don't "enable" until the form button is clicked a 2nd time (and then I see all the console messages again). I tried 2 different methods, from within getGoogle(), both worked exactly the same - 1st clicked fired all functions correctly, but tabs did not enable. 2nd click fired all the functions and then the tabs got enabled.
Try this previous answer. Are you using $http calls? If so I have never actually had to do that so it seems like something else might be the root cause.
UPDATE
How about creating an Angular Service for this GetGoogle function call. Then you will still be inside of angular and can inject $rootScope and anything else that you need. You will need to inject this service into your tab1Ctrl (the myGoggleService below). I would also probably just pass the form back on the ng-submit:
Html
ng-submit="setInfo(formNameGoesHere)"
Controller
.controller('tab1Ctrl', function($scope, $rootScope, myGoogleService) {
$scope.setInfo = function(form) {
myGoogleService.getGoogle(form);
}
$scope.enableTabs = function(type) {
console.log("Here enableTabs1");
$rootScope.$broadcast('updateTabsRefresh');
console.log("Here enableTabs2");
}
});
Service: If you haven't created any already you will need to register it in your app.js like any directives you have and also put them in your index.html page like a regular controller.
.service('myGoggleService', [ '$rootScope', function ($rootScope) {
this.getGoogle = function(userInfo,clear) {
console.log("setInfo 1") ;
geoCoder.geocode({'address': userInfo}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
$rootScope.$broadcast("updateTabsRefresh");
} else {
}
});
}
}}]);
I did copy your code from above and then just removed some of the extra stuff just to get the point across. Obviously could not run the code so there might be some mistakes or slight changes needed, but hopefully this will get you close.

angular ui-router go to URL

How to use $state.go() if I have just the URL ?
Or can I get a state based on URL? (and than use $state.go(state))
I'm asking because I had to intercept the $urlRouterProvider.otherwise() to wait for an other plugin loads some external modules.. and now I need to continue and call the URL that call otherwise()
In place of $state.go(), you can use $location service as well.
i.e.
$location.path(url)
Please take care of not using # in URL. You can also use window.location.href
I had a similar problem, and $location wasn't helping, so I wrote a function to get the state from the url.
NB: I am using nested states based on ui-router.stateHelper, so I traverse my nested states object, testing for url matches. It would be slightly different when using dot notation to define nested states - and even easier if you don't use nested states at all!
function goPath (path) {
var target;
var arr = path.match(/\/\w+/g);
var i = 0;
var testState = function (state, i) {
if (state.url === arr[i]) {
target = state;
if (state.children && state.children.length && arr.length > i+1) {
i++;
state.children.forEach( function (childState) {
testState(childState, i);
});
}
}
};
myStatesObj.forEach( function (state) {
testState(state, i);
});
$state.go(target.name);
};
I was on a similar situation, what I did is changed the location to a different path and reset it to the current after a timeout like this
var path = $location.path();
$location.path("/");
$timeout(function(){
$location.path(path).replace(); //use .replace() so the empty path won't go to the history
},0);
i'm adding a full answer to this due to the high number of views.
NOTE: location.search() is only used where you need to handle a URL with a query string in it. otherwise use location.path() only.
your ui.router login state should look something like ...
.state('login', {
url: '/login',
templateUrl: 'routes/login/login.html',
controller: 'LoginController',
controllerAs: 'loginCtrl',
authenticate: false,
params: {
fwdPath: undefined, // Location to forward to on login success
fwdQueryStringObject: undefined // Query string object to use on login success - retrieved from $location.search()
}
})
your 401 (unauthorised) interceptor should look something like ...
state.go('login', {fwdPath: location.path(), fwdQueryStringObject: location.search()});
your login controllers login function should call your login service's login function. the code INSIDE the controllers login function should look something like ...
loginService.login(self.username, self.password).then(function (response) {
// local vars prevent unit test failure
var fwdPath = state.params.fwdPath;
var fwdQueryStringObject = state.params.fwdQueryStringObject;
if (response.status === 200) {
timeout(function () {
if (fwdPath != null) {
location.path(fwdPath).search(fwdQueryStringObject);
location.replace();
} else {
state.go('home');
}
}, 400);
} else {
self.error = true;
}
self.pending = false;
}
};
and finally your unit tests ...
state.params.fwdPath = '/login/list';
state.params.fwdQueryStringObject = {q: 5};
spyOn(location, 'path').and.callThrough();
spyOn(location, 'search').and.callThrough();
...
expect(location.path).toHaveBeenCalledWith('/login/list');
expect(location.search).toHaveBeenCalledWith({q: 5});

AngularJS - change $location silently - remove query string

Is there any way to silently change the route in the url bar using angular?
The user clicks a link for the email that goes to:
/verificationExecuted?verificationCode=xxxxxx
When the page loads I want to read the verificationCode and then clear it:
if($location.path() == '/verificationExecuted'){
this.registrationCode = this.$location.search()["verificationCode"];
this.$location.search("verificationCode", null); //Uncomment but make this silent!
if(registrationCode != null) {
....
}
else $location.path("/404");
}
What happens when I clear it is the remaining part of the route ("/verificationExecuted") remains buts the route re-triggers so it comes around again with no verificationCode and goes straight to 404.
I want to remove the code without doing anything else.
You can always set the reloadOnSearch option on your route to be false.
It will prevent the route from reloading if only the query string changes:
$routeProvider.when("/path/to/my/route",{
controller: 'MyController',
templateUrl: '/path/to/template.html',
//Secret Sauce
reloadOnSearch: false
});
try this
$location.url($location.path())
See documentation for more details about $location
I had a similar requirement for one of my projects.
What I did in such a case was make use of a service.
app.factory('queryData', function () {
var data;
return {
get: function () {
return data;
},
set: function (newData) {
data = newData
}
};
});
This service was then used in my controller as:
app.controller('TestCtrl', ['$scope', '$location', 'queryData',
function ($scope, $location, queryData) {
var queryParam = $location.search()['myParam'];
if (queryParam) {
//Store it
queryData.set(queryParam);
//Reload same page without query argument
$location.path('/same/path/without/argument');
} else {
//Use the service
queryParam = queryData.get();
if (queryParam) {
//Reset it so that the next cycle works correctly
queryData.set();
}
else {
//404 - nobody seems to have the query
$location.path('/404');
}
}
}
]);
I solved this by adding a method that changes the path and canceling the event.
public updateSearch(){
var un = this.$rootScope.$on('$routeChangeStart', (e)=> {
e.preventDefault();
un();
});
this.$location.search('new',search.searchFilter);
if (!keep_previous_path_in_history) this.$location.replace();
}

Passing current tab url to server in angular resources fetch

I am trying to send the current tab url to the resource service { in param } .
but the global tablUrl is not having any value at
var url = "http://[localhost]/getProfile?domain="+tabUrl
but getting logged corrent at :
console.log(tabUrl);
this is my code :
var tabUrl;
angular.module('jsonService', ['ngResource'])
.factory('JsonService', function($resource) {
chrome.tabs.getSelected(null, function(tab) {
tabUrl = tab.url;
console.log(tabUrl);
});
var url = "http://[localhost]/getProfile?domain="+tabUrl
return $resource(url,{}, {
list : {
method : 'GET',
cache : true
}
});
});
template binding :
<body ng-controller="extensionCtrl">
this is controller :
app.controller('extensionCtrl', function($scope , JsonService) {
JsonService.get(function(data){
$scope.data = data;
});
});
First:
Please, don't use the deprecated chrome.tabs.getSelected. Use chrome.tabs.query instead.
Second:
chrome.tabs.getSelected/chrome.tabs.query are asynchronous. This means that execution continues while they do some work in the background and the specified callback is called when they are done.
So, in a case like this:
line 1: chrome.tabs.getSelected(null, funkyCallback);
line 2: var url = ...
line 3: return $resource(...);
...a possible (and very probable) order of execution is:
1. chrome.tabs.getSelected (starts retrieving the active tab in the background)
2. line 2 gets executed (at this time 'tabURL' is not set yet)
3. line 3 gets executed (returning something)
4. Once the the active tab is retrieved, 'funkyCallback' is called
(setting 'tabURL' after it is too late).
When using asynchronous APIs (such as most of the chrome.* APIs), you have to change the whole logic of your scripts to be in line with the asynchronous nature of the API calls.
E.g., you could achieve the same result like this:
HTML:
<html ng-app="jsonService">
...
<body ng-controller="extensionCtrl">
<p>{{jsonData}}</p>
...
JS:
var app = angular.module("jsonService", ["ngResource"]);
app.factory("JsonFactory", function($resource) {
var url = "http://localhost/getProfile?domain=:tabUrl";
var retObj = $resource(url, {}, {
list: {
method: "GET",
cache: true
}
});
return retObj;
});
app.controller("extensionCtrl", function($q, $rootScope, JsonFactory) {
chrome.tabs.query({ active: true }, function(tabs) {
JsonFactory.list({ tabUrl: tabs[0].url }, function(data) {
// On success...
$rootScope.jsonData = data;
}, function(data) {
// On error...
$rootScope.jsonData = "Error using JsonFactory.list(...) !";
});
});
});
See, also, this short demo that does something similarly asynchronous

Resources