During loading of the partial Html with controller, my function named $scope.actionViewVisitors() is recognized and runs without errors. But whenever I use it inside another function on the same controller, it gives me an error:
TypeError: $scope.actionViewVisitors is not a function. Please see my code below:
angular.module("Visitor.controller", [])
// ============== Controllers
.controller("viewVisitorController", function ($scope, $rootScope, $http, viewVisitorService, viewAccountService, DTOptionsBuilder) {
$scope.visitorList = null;
$scope.viewAccountDetail = null;
$scope.avatar = null;
$scope.visitorDetail = null;
$scope.visitorBtn = "Create";
$scope.actionViewAccount = function () {
$scope.actionViewAccount = viewAccountService.serviceViewAccount()
.then(function (response) {
$scope.viewAccountDetail = response.data.account;
$scope.avatar = "../../avatars/" + response.data.account.AccountId + ".jpg";
})
}
$scope.dtOptions = DTOptionsBuilder.newOptions()
.withDisplayLength(10)
.withOption('bLengthChange', false);
// THIS ONE IS NOT RECOGNIZED
$scope.actionViewVisitors = function () {
$scope.actionViewVisitors = viewVisitorService.serviceViewVisitors()
.then(function (response) {
debugger;
$scope.visitorList = response.data.visitorList;
});
}
// I DON'T GET ANY ERROR HERE
$scope.actionViewVisitors();
$scope.actionViewAccount();
$scope.createVisitor = function () {
$scope.statusMessage = null;
if ($scope.visitorBtn == "Create") {
$scope.createVisitor = viewVisitorService.serviceCreateVisitor($scope.visitorDetail)
.then(function (response) {
if (response.data.response == '1') {
bootbox.alert({
message: "Successfully created a new visitor.",
size: 'small',
classname: 'bb-alternate-modal'
});
} else if (response.data.response == '0') {
bootbox.alert({
message: "Failed in creting visitor.",
size: 'small',
classname: 'bb-alternate-modal'
});
}
});
debugger;
$scope.visitorDetail = undefined;
// I GET THE ERROR WHEN I CALL THIS METHOD
$scope.actionViewVisitors();
}
}
})
// ============== Factories
.factory("viewVisitorService", ["$http", function ($http) {
var fac = {};
fac.serviceViewVisitors = function () {
return $http({
url: '/Visitor/ViewVisitors',
method: 'get'
});
}
fac.serviceCreateVisitor = function(visitor) {
return $http({
url: '/Visitor/CreateVisitor',
data: { visitor: visitor },
method: 'post'
});
}
return fac;
}])
You are overwriting the function with Promise in the following line, thus the error is correct
$scope.actionViewVisitors = function () {
$scope.actionViewVisitors = viewVisitorService.serviceViewVisitors()
.then(function (response) {
$scope.visitorList = response.data.visitorList;
});
}
Remove $scope.actionViewVisitors =
$scope.actionViewVisitors = function () {
viewVisitorService.serviceViewVisitors()
.then(function (response) {
$scope.visitorList = response.data.visitorList;
});
}
On the first call to the function you are changing it from a function to a Promise. Maybe you want to be returning the result instead?
$scope.actionViewVisitors = function () {
return viewVisitorService.serviceViewVisitors()
.then(function (response) {
debugger;
$scope.visitorList = response.data.visitorList;
});
}
Related
I'm trying to learn AngularJS and I have the following service that works, but I'm wondering if there's a better way of writing it that is simpler and involves less duplication of code. Can you think of anything?
The service:
app.service("myService", function ($http) {
this.callData1 = function () {
var url = myurl1;
function getData() {
return $http.get(url);
}
return {
getData: getData,
}
},
this.callData2 = function () {
var url = myurl2;
function getData() {
return $http.get(url);
}
return {
getData: getData,
}
},
this.callData3 = function () {
var url = myurl3;
function getData(var1, var2) {
return $http({
url: url,
method: "GET",
params: { var1: var1, var2: var2 }
});
}
return {
getData: getData,
}
}
});
My controller:
app.controller("myController", function ($scope, myService) {
myService.callData1().getData().then(function (response) {
$scope.var1 = response.data;
});
myService.callData2().getData().then(function (response) {
$scope.var2 = response.data;
});
var var1 = "something";
var var2 = "something else";
myService.callData3().getData(var1, var2).then(function (response) {
$scope.var3 = response.data;
});
});
You can generalize it as follows:
app.service("myService", function ($http) {
this.getData = function(url, method, params){
var httpParams = {
url: url,
method: method || "GET", // If method is skipped, use "GET" by default
params: params || {} // If no params are given, take {}
};
return $http.get(httpParams);
};
});
And in controller, you can use this service as follows:
app.controller("myController", function ($scope, myService) {
var url = "https://blahblah";
myService.getData(url).then(function (response) {
$scope.var1 = response.data;
});
var params = {var1: "something", var2: "something2"};
myService.getData(url, "POST", params).then(function (response) {
$scope.var1 = response.data;
});
});
i'm developing an app that received from a server a JSON array and divided data in a specific way, i've a portion of code that works if i use it alone but if i tried to insert it in an application it doesn't work.
This is my code:
ionicApp.controller('DefaultController', DefaultController)
.factory('dataService', dataService);
DefaultController.$inject = ['dataService', '$http'];
function DefaultController(dataService, $http) {
var vm = this;
console.log("Dentro ctrl");
getEvents();
function getEvents() {
console.log("Dentro getEvents");
return dataService.getEvents()
.then(function (data) {
console.log("data: " + data);
vm.data = data;
console.log("vm.data: " + vm.data);
return vm.data;
});
}
vm.submit = function (){
console.log("funzione");
console.log(vm.form);
var data = vm.form; // IMPORTANT
//console.clear();
var link = 'http://localhost/<path>/api/apiDoFix.php';
var mail = window.localStorage.getItem("mail");
var scelta = window.localStorage.getItem("scelta");
console.log(data);
console.log ("EMAIL" + mail);
console.log ("SCELTA" + scelta);
$http.post(link, {giorno: data.giorno, ora: data.ora, mail: mail, scelta: scelta})
.then(function (res){
console.log("Dentro http.post");
var response = res.data;
if (response != 'F'){
console.log("Dentro if");
console.log(response);
//window.location.href ="/#/main";
} else {
console.log("Dentro else");
}
});
};
}
dataService.$inject = ['$http'];
function dataService($http) {
console.log("qua");
var service = {
getEvents: getEvents
};
return service;
function getEvents() {
console.log("qua2");
var config = {
transformResponse: function (data, headers) {
var result = {
events: [],
schedules: []
};
var events = JSON.parse(data);
var dates = [];
console.log("qua3");
for (var i = 0; i < events.length; i++) {
if (dates.indexOf(events[i].day) === -1) {
var date = events[i].day;
dates.push(date);
result.events.push({
date: date
});
}
result.schedules.push({
date: events[i].day,
time: events[i].time
});
}
console.log("result: " + result);
return result;
}
};
return $http.get('http://localhost/ShuttleFIX/api/apiTimes.php', config)
.then(getEventsCompleted)
.catch(getEventsFailed);
function getEventsCompleted(response) {
console.log("response " + response.data);
return response.data;
}
function getEventsFailed(error) {
console.error(error);
}
}
}
is it possible to rewrite this code in a controller function without using factory?
Thank's
I have a problem with nested promises, inside an angular service I have this method:
this.get = function (matchId, teamId) {
var _key = matchId + '_' + teamId;
var self = this;
var alivePromise = $apiService.alive();
alivePromise.success(function () {
var getPromise = $apiService.get(matchId, teamId);
getPromise.success(function (response) {
self.clearLocal().then(function () {
return self.pushToLocal({ ots: _key, data: response })
.then(function () {
return self.fetchFromLocal(_key);
});
})
});
getPromise.error(function (response) {
return self.fetchFromLocal(_key);
});
});
alivePromise.error(function () {
return self.fetchFromLocal(_key);
});
};
this.fetchFromLocal = function (key) {
return $indexedDB.openStore('teamsheets', function (store) {
store.find(key);
});
}
this.pushToLocal = function (data) {
return $indexedDB.openStore('teamsheets', function (store) {
store.upsert(data);
});
};
Inside a controller I'd like call this method in this manner:
$dataProvider.get(MATCH_ID, TEAM_ID)
.then(function (result) {
$scope.teamsheet = result;
$scope.masterCopy = JSON.parse(JSON.stringify(result));
});
But I retrieve always the following error:
angular.min.js:107 TypeError: Cannot read property 'then' of undefined
at new <anonymous> (team-sheet-details-controller.js:3)
at Object.e [as invoke] (angular.min.js:39)
at Q.instance (angular.min.js:80)
at L (angular.min.js:61)
at g (angular.min.js:54)
at g (angular.min.js:54)
at angular.min.js:53
at angular.min.js:20
at m.$eval (angular.min.js:132)
at m.$apply (angular.min.js:133)
What I am doing wrong?
if this.get is your get function on $dataProvider then try this code:
this.get = function (matchId, teamId) {
var _key = matchId + '_' + teamId;
var self = this;
return $apiService.alive().then(function () {
return getPromise = $apiService.get(matchId, teamId);
getPromise.success(function (response) {
self.clearLocal().then(function () {
return self.pushToLocal({ ots: _key, data: response })
.then(function () {
return self.fetchFromLocal(_key);
});
})
});
getPromise.error(function (response) {
return self.fetchFromLocal(_key);
});
}, function () {
return self.fetchFromLocal(_key);
});
};
I am trying to make sync calls using a factory pattern.
$scope.doLogin = function (username, password, rememberme) {
appKeyService.makeCall().then(function (data) {
// data = JSON.stringify(data);
debugAlert("login controller app key service"+data);
var appkeyvalue = data.d.appkey;
sessionConfigurationService.setBasicToken(appkeyvalue);
loginService.makeCall(username, password, rememberme).then(function (accessTokenData) {
if (accessTokenData.access_token !== "")
{
sessionConfigurationService.setAccessTokenData(accessTokenData.access_token);
userPreferencesService.makeCall().then(function (userPreferencesData) {
if (userPreferencesData.d.userId !== "")
{
sessionConfigurationService.setUserPreferences(userPreferencesData.d);
// $window.location.href = '/base.html';
}
});
}
});
});
};
My appKeyService factory is
app.factory('appKeyService', function ($q, authenticatedServiceFactory, configurationService) {
var deffered = $q.defer();
var service = {};
service.makeCall = function () {
debugAlert("appKeyService async method request start");
authenticatedServiceFactory.makeCall("GET", configurationService.getAppKeyURL(), "", "").then(function (data) {
debugAlert("appKeyService async method response")
deffered.resolve(data);
});
return deffered.promise;
};
return service;
});
My authenticated service factory is
app.factory('authenticatedServiceFactory', function ($http, $q, sessionConfigurationService) {
var deffered = $q.defer();
var service = {};
service.makeCall = function (methodType, URL, data, authType) {
var headerValue = "";
if (authType === "Basic") {
headerValue = sessionConfigurationService.getBasicToken();
} else if (authType === "Bearer") {
headerValue = sessionConfigurationService.getBearerToken();
}
var config = {headers: {
'Authorization': headerValue,
'Accept': 'application/json;odata=verbose',
},
withCredentials: true,
async: false
};
if (methodType === "GET") {
$http.get(URL, data, config)
.then(function (getData) {
debugAlert("GET method response" + JSON.stringify(getData));
deffered.resolve(getData.data);
}, function (error) {
debugAlert("GET method response error" + JSON.stringify(error));
deffered.reject(error);
});
}
else if (methodType === "POST") {
$http.post(URL, data, config)
.then(function (putData) {
debugAlert("POST method response" + JSON.stringify(putData));
deffered.resolve(putData.data);
}, function (error) {
debugAlert("POST method response error" + JSON.stringify(error));
deffered.reject(error);
});
}
else if (methodType === "DELETE") {
$http.delete(URL, data, config)
.then(function (deleteData) {
debugAlert("DELETE method response" + JSON.stringify(deleteData));
deffered.resolve(deleteData.data);
}, function (error) {
debugAlert("DELETE method response error" + JSON.stringify(error));
deffered.reject(error);
});
}
else if (methodType === "PUT") {
$http.put(URL, config)
.then(function (putData) {
debugAlert("PUT method response" + JSON.stringify(putData));
deffered.resolve(putData.data);
}, function (error) {
debugAlert("PUT method response error" + JSON.stringify(error));
deffered.reject(error);
});
}
return deffered.promise;
};
return service;
});
But I don't see the service calls are made in sync. So the "then" part in the controller is not executing after we receive the response. Its executing one after the other. How can I make that happen.
#Frane Poljak
Thank you for your comment. I just brought
var deffered = $q.defer();
inside the makeCall method and its working as I wanted now. Thank you!
app.factory('appKeyService', function ($q, authenticatedServiceFactory, configurationService) {
var service = {};
service.makeCall = function () {
var deffered = $q.defer();
debugAlert("appKeyService async method request start");
authenticatedServiceFactory.makeCall("GET", configurationService.getAppKeyURL(), "", "").then(function (data) {
debugAlert("appKeyService async method response")
deffered.resolve(data);
});
return deffered.promise;
};
return service;
});
I am trying to stub several ajax calls, but I want to have both beforeSend and success executed, is this possible?
I want something like this:
var stub = sinon.stub(jQuery, "ajax");
stub.onCall(0).yieldsTo("beforeSend").yieldsTo("success", {some: 'data'});
stub.onCall(1).yieldsTo("beforeSend").yieldsTo("success", {other: 'stuff'});
But this skips the 'beforeSend' method.
I know it would be easier to allow ajax to do it's stuff and use sinon's fakeServer, but I can't as I'm testing in Node with a fake browser and it just doesn't work
You could use yieldTo after the call:
var stub = sinon.stub();
stub({
foo: function() {
console.log('foo');
},
bar: function() {
console.log('bar');
}
});
stub.yieldTo('foo');
stub.yieldTo('bar');
I was able to work around this by adding some additional code:
var responses = {};
var executionComplete;
beforeEach(function () {
executionComplete = $.Deferred();
sinon.stub($, "ajax", function (options) {
if (options.beforeSend) {
options.beforeSend();
}
completeAjaxCall(options);
});
});
afterEach(function () {
$.ajax.restore();
});
var completeAjaxCall = function (options) {
var response = findResponse(options.url, options.type);
setTimeout(function () {
if (response.code < 400) {
if (options.dataFilter && response.data) {
response.data = options.dataFilter(JSON.stringify(response.data));
}
if (options.success) {
options.success(response.data);
}
} else {
if (options.error) {
options.error(response.data);
}
}
if (options.complete) {
options.complete();
}
if (response.completeExecution) {
executionComplete.resolve();
}
}, response.serverResponseTime);
};
var findResponse = function (url, type) {
var response = responses[url];
expect(response, url + ' should have a response').to.exist;
expect(response.type).to.equal(type);
delete responses[url];
if (Object.keys(responses).length === 0) {
response.completeExecution = true;
}
return response;
};
var givenResponse = function (response) {
responses[response.url] = response;
};
Then in my test I can use it like this:
it('should do some stuff', function (done) {
//given
givenResponse({serverResponseTime: 4, code: 200, url: '/saveStuff', type: 'POST'});
givenResponse({serverResponseTime: 1, code: 200, url: '/getStuff', type: 'GET'});
//when
$('button').click();
//then
executionComplete.then(function () {
expect(something).to.be.true;
done();
});
});