This is a follow-up question to Angular-ui modal, sending data into modal controller from $http
I have the following code where I want to get data via a factory to the modal.
$scope.docSetup = function() {
var modalInstance = $modal.open({
templateUrl : '/templates/dialog/docSetup.html',
controller : 'docSetupDlgCtrl',
resolve : {
dlgData : function(){
return TagService.list($scope.publication.id);
}
}
});
modalInstance.result.then(function (dlgData) {
$log.debug(dlgData);
}, function () {
$log.debug('Modal dismissed at: ' + new Date());
});
};
And here is the factory:
app.factory("TagService", function($http, $log){
return {
list: function(selectedDoc){
$log.info("Tag service at work => list");
var httpPromise = $http.post("tags/list", { publicationId: selectedDoc });
httpPromise.then(function (response) {
$log.log(response.data);
return response.data;
}, function (error) {
$log.error(error);
});
}
}
});
The above isn't resolving any data into dlgData. The factory is producing data and if I hardcode the data object into the 'resolve' function, it passes it.
return the entire httpPromise as well:
return httpPromise.then(function (response) {
$log.log(response.data);
return response.data;
}, function (error) {
$log.error(error);
});
Related
I'm working on a very modularized project and currently I'm building an Element Directive which changes templateUrl based on user login/logout.
To do that, I'm trying to execute a Factory's Function inside templateUrl. That particular functions calls another method from a JWT Factory and returns true if the user is logged or false if not.
Then, If in my templateUrl I receive true, I pick a certain url, if false another one.
But, sadly, I receive the following error:
[$http:badreq] Http request configuration url must be a string. Received: {}
All $log.log() print the correct result.
Of course, it won't render nor page1 nor page2
Directive
(function () {
'use strict';
angular
.module('myApp')
.directive('myDirective', ['SessionCheckerFactory', function (SessionCheckerFactory) {
return {
restrict: 'E',
templateUrl : function(){
return SessionCheckerService.checkSession().then( function (res) {
console.log(res);//true
return res ? 'app/page1.html' : 'app/page2.html';
});
},
controller : 'MyController',
controllerAs : 'myCtrl',
bindToController : true
};
}]);
})();
SessionCheckerFactory
(function () {
'use strict';
angular
.module('myApp')
.factory('SessionCheckerFactory', function (AuthTokenFactory) {
function checkSession() {
return AuthTokenFactory.isAuth();
}
return {
checkSession: checkSession
}
});
})();
AuthTokenFactory
(function() {
'use strict';
angular.module('myApp')
.factory('AuthTokenFactory', function AuthTokenFactory(store, $cookies) {
//Takes user's info from LocalStorage, if not empty returns a String with encoded string informations
function getToken() {
if (store.get(key)) {
return store.get(key);
}
//Takes user's info from cookie
var token = $cookies.get('token', {path: '/'});
store.set(key, token);
return token;
}
//If getToken is empty returns false, else true
function isAuth() {
return Promise.resolve(Boolean(getToken()));
}
return {
isAuth : isAuth,
getToken : getToken
}
});
})();
I read around that this problem is usually generated by $http requests, but that's not my case. I didn't find any solution to that so far.
How can I fix this?
Thanks in advance.
Then, If in my templateUrl I receive true, I pick a certain url, if false another one.
Actually you don't. If you receive true, you pick one url, if some truthy value, another url, and if something falsy then you don't pick any url:
if (res) {
if (res === true) {
return resolve('app/page1.html');
} // else
return resolve('app/page2.html');
}
// else return undefined;
You probably want
templateUrl : function(){
return SessionCheckerFactory.checkSession().then(function (res) {
if (res) {
return 'app/page1.html';
} else {
return 'app/page2.html';
}
})
},
I managed to fix the issue using a link function and $templateRequest
Directive
link: function (scope, element) {
SessionCheckerService.renderTemplate().then(function (temp){
$templateRequest(temp).then(function (requestedTemplate) {
element.html(requestedTemplate);
$compile(element.contents())(scope);
});
});
}
Factory
var templateConfig = './app/config/templates.config.json';
function getTemplate(){
return $http.get(templateConfig)
.then(function(templates) {
return templates.data;
});
}
function checkSession() {
return Promise.resolve(AuthTokenFactory.isAuth());
}
function whichTemplate(template, result) {
var myTemplate = '';
if(result){
myTemplate = template.logIn;
} else {
myTemplate = template.logOut;
}
if(myTemplate){
return Promise.resolve(myTemplate);
}
}
//Chaining the methods and returning the correct template
function renderTemplate() {
return new Promise(function (resolve) {
checkSession().then(function(isAuth){
getTemplate().then( function(templates){
whichTemplate(templates, isAuth).then( function (temp) {
return resolve(temp);
});
});
});
});
}
return {
renderTemplate : renderTemplate
}
Templates Config
{
"logOut" : "app/page1.html",
"logIn" : "app/page2.html"
}
I hope It'll be helpful.
i have created the custom service like this
app.service('userService', function($http,UrlService) {
return {
init: function(callback) {
$http.get(UrlService.baseUrl +'/api/users/list').then(function(user_response) {
callback(user_response);
});
}
}
})
Inside of my project main controller i have used like this to get the angular material design modal.
$scope.replyComplaint = function(user,complaint_id) {
complaint_id=user._id;
console.log(complaint_id)
$mdDialog.show({
controller: DialogCtrl,
templateUrl: 'submodules/user_management/replydialog.html',
resolve: { complaint_id : function() {return complaint_id;} },
locals: {
users: $scope.users
},
parent: angular.element(document.body),
clickOutsideToClose: true,
})
.then(function(response) {
$scope.response = response;
console.log(response);
}, function() {
//fail
});
};
created another controller for dialog as in the angular material docs as follows
function DialogCtrl($scope, $rootScope, $mdDialog, users,complaintService, UrlService, $http) {
complaintService.init(function(complaint_response) {
$scope.complaints = complaint_response.data;
$scope.getUsers();
});
$scope.getUsers = function(complaint_id) {
console.log(complaint_id);
$scope.hide = function() {
$mdDialog.hide();
};
$scope.cancel = function() {
$mdDialog.cancel();
};
$scope.replyMail = function(complaint_id) {
console.log(complaint_id);
$http.post(UrlService.baseUrl + '/api/complaints/complaint/'+complaint_id , {
complaint: "replyText"
}, $scope)
.then(function(response) {
console.log(name);
$state.reload();
}, function(response) {
console.log(name);
});
}
}
}
Now, i need to get the user_response data in DialogController. if i put console.log('$scope.users') inside of this userservice.init function, i can get the data. but not outside of it. how to get the response data outside of the userService.init function
userService.init(function(user_response) {
$scope.users = user_response.data;
}); //this is added in DialogController
Main intension is to get the user.comlaint_id in the post request of reply mail function . that user.complaint_id is a part of the user_response
Anyone please help me. Thanks
The $http.get call returns a promise, you can just use that.
app.service('userService', function($http,UrlService) {
return {
init: function(callback) {
return $http.get(UrlService.baseUrl +'/api/users/list');
}
}
});
Controller:
function Dialog($scope,$rootScope, $mdDialog,userService,UrlService,$http) {
// console.log(userService.init());
init();
function init() {
userService.init().then(function(response) {
$scope.users = response.data;
});
}
}
This also has the advantage of easier error handling:
function Dialog($scope,$rootScope, $mdDialog,userService,UrlService,$http) {
// console.log(userService.init());
init();
function init() {
userService.init().then(function(response) {
$scope.users = response.data;
}, function(error) {
// handle error
});
}
}
You should read up on angular/javascript promises and their chaining mechanism: angular promises
Here is the solution
userService.init(function(user_response) {
$scope.users = user_response.data;
$scope.init();
});
$scope.init = function() {
You can access $scope.users here
}
Call any method instead of init() in which you require $scope.users
I have a SPA with two different views one for subjects and one for student,
in subject view I have a save button in app/views/subject/subject.html:
<button type="button" class="btn btn-warning" ng-click="saveInfo()">
Save
</button>
I want to add the same function in the student views , saveInfo() pass the data into a service in the app factory which save the data in DB through fill_table.php.
the app factory in app/javascript/services.js:
var app = angular.module('myApp');
app.factory("services", ['$http', function($http) {
var serviceBase = 'http://localhost/php/';
var obj = {};
document.title = "myApp on " + serviceBase;
obj.postData = function (user, data) {
return $http.post(serviceBase + 'fill_table.php', { "data": data, "user": {'username': user.name, 'password': user.password }).then(function (results) {
return results.data;
});
};
saveInfo() is in app/views/subject/subject.js:
$scope.saveInfo = function() {
console.log("saveInfo");
$scope.loadingInstance = $modal.open({
animation: $scope.animationsEnabled,
templateUrl: 'modalLoading.html',
size: "l",
});
return getChanges( $indexedDB, $q).then( function(responsesArray) {
var jsonData = {};
$scope.errorInstance = undefined;
for (var i=0; i < DB_TABLES.length; i++) {
var table = DB_TABLES[i];
var items = responsesArray[i]
if (items.length > 0){
jsonData[table] = items;
}
}
console.log(JSON.stringify(jsonData));
return services.postData($scope.selectedUser, jsonData);
})
}
I want to add the mentioned button into app/views/student/student.html. i tried and copied the code from the subject.js into Student but for some reason it does not work eventhough i checked everything was correct so is there a way to only that function from subject.js into Student.html
note 1 getChanges() is another function get the inserted info and pass it into saveinfo().
note 2 right now I can save the info inserted student view by pressing save button in subject view
If I understand you correctly, you have two html files and two controller (student and subject). To share data/functions between these, you could use a service or factory to handle all your http request. This is reusable and accessible from all your controllers.
app.factory("services", ['$http', function($http) {
var postStudent = function (student) {
return $http.post("api/Student/Post", student);
};
var getChanges = function (){
return $http.get("api/Student/Changes", student);
};
return {
postStudent : postStudent,
getChanges : getChanges
};
}])
Now you can use can call the services from your controller as you see fit.
app.controller('StudentController', ['service', function(service){
service.postStudent(student).then(function successCallback(response) {
console.log('success');
}, function errorCallback(response) {
console.log('error ' + response);
});
service.getChanges().then(function successCallback(response) {
console.log('success');
}, function errorCallback(response) {
console.log('error ' + response);
});
}]);
app.controller('SubjectController', ['service', function(service){
service.postStudent(student).then(functionsuccessCallback(response){
},
function errorCallback(response) {
});
service.getChanges().then(function successCallback(response) {
},
function errorCallback(response) {
});
}]);
Note that the above has not been implemented, but should provide you with an outline.
Im just starting on AngularJS. I'm not sure how to churn this out. I'm trying to include multiple functions within one service. (I hope this is not against bad practice.)
The following is my working code:
myDataService.async().then(function (d) {
$scope.dbCalls = d.d;
});
My Service:
app.factory('myDataService', function ($http) {
// How do you get this bottom line to work?
// this.getAllCalls = function () {
var myService = {
async: function () {
var promise = $http.post('AngularTest.aspx/FetchCalls', { data: {} }).then(function (response) {
console.log(response);
return response.data;
});
return promise;
}
};
return myService;
//}; <--Commented out for clarity
});
Thanks!
you just return an object with properties from the service, then you are able to call those properties as different service methods
like so:
.service('myService', function() {
return {
firstMethod: function() { ... },
secondMethod: function() { ... },
thirdMethod: function() { ... }
}
})
and in the controller/directive
.controller('myCtrl', function(myService) {
myService.firstMethod();
myService.secondMethod();
myService.thirdMethod();
})
I have a service which will make a call to the server and returns the data. I am binding service to a variable on scope.
Example:
Let the service be DataModelService
in the controller : $scope.data = DataModelService
in the view <div ng-repeat="value in data.persons">{{value.name}}</div>
My Code :
This is how my code looks like:
/**DataModelService**/
factory('DataModelService', [
'DataService',
function (DataService) {
var service;
service = {
changeState: function (params) {
DataService.changePersonState(params)
.then(function (response) {
service.loadData(response.data);
});
},
loadData: function (responseData) {
service.persons = responseData.persons;
}
}
return service;
}
]);
/**DataService**/
factory('DataService', ['$http',
function ($http) {
return {
changePersonState: function (params) {
return $http.post("url", params);
}
}
}
]);
/**DataController**/
.controller('DataController', ['DataModelService',
function (DataModelService) {
$scope.data = DataModelService;
}
]);
/view/
<div ng-repeat = "person in data.persons" >{{person.name}} </div>
On the view I am doing a ng-repeat on a key in data i.e. ng-repeat="value in data.persons"
and also I have an option to change the state of person to active or inactive, so whenver i make a change to the state of the person, a call is sent to the server and data is set into the Service and as it is binded to the view, it should automatically update the data. But whats happening in my case, ng-repeat is not removing old data and instead it is appending new data to the old data.
For me its not good approach to write promise callback (then) into service. Because in your case, DataModelService returns data with some delay but not promise. And we don't know when.
So the way to make it work to add basic $timeout and fetch data from service by using other method.
So my suggestion is Demo
and your fixed example: Demo2
If we will take your example, it should be like:
JS
var fessmodule = angular.module('myModule', ['ngResource']);
fessmodule.controller('fessCntrl', function ($scope, DataModelService, $timeout) {
$scope.alertSwap = function () {
DataModelService.changeState('ff');
$timeout(function(){
$scope.data = DataModelService.getResponse();
}, 10);
}
});
fessmodule.$inject = ['$scope', 'Data', '$timeout'];
/**DataModelService**/
fessmodule.factory('DataModelService', [ 'DataService',function (DataService) {
var value = [];
var service = {
changeState: function (params) {
DataService.changePersonState(params)
.then(function (response) {
value = response.persons;
});
},
getResponse : function(){
return value;
}
}
return service;
}
]);
/**DataService**/
fessmodule.factory('DataService', ['$q',function ($q) {
var data = { // dummy
persons: [{
name: "Bob"
}, {
name: "Mark"
}, {
name: "Kelly"
}]
};
var factory = {
changePersonState: function (selectedSubject) {
var deferred = $q.defer();
deferred.resolve(data);
return deferred.promise;
}
}
return factory;
} //function
]);