How do i pass data from the controller to a component to show to the user?
app.js
(function(angular) {
'use strict';
angular.module('app', []).controller('MainCtrl', function MainCtrl($scope, $http) {
$http({
method: 'GET',
url: '/team',
}).then(function successCallback(response) {
console.log(response.data);
this.teams = response.data;
$scope.teams = response.data;
// var keys = Object.keys($scope.agendaEventData);
// $scope.eventslength = keys.length;
}, function errorCallback(response) {
});
}).config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
}]);
})(window.angular);
component
(function(angular) {
'use strict';
angular.module('app').component('bringTeamToEvent', {
templateUrl: '/assets/ng/app/team/bringTeamToEvent.html',
bindings: {
teams: '<'
},
});
})(window.angular);
Template
{{$ctrl.teams}}
{{teams}}
The data is coming from the api no problems, i do not understand the complexity to get it to work.
Learning from https://docs.angularjs.org/tutorial/step_13
and https://docs.angularjs.org/guide/component#!
Setting the data on this.teams is correct, and correct to access it like $ctrl.teams. The issue here is that your $http callback functions are injecting their own function context so that this doesn't refer to the component.
For this reason, it's generally good practice to use arrow functions for callback functions:
$http({
method: 'GET',
url: '/team',
}).then(response => {
this.teams = response.data;
}, response => {
});
Here is a demo
Related
I need to call php file using service/Factory method using Angular.js. Here instead of calling $http repeatedly in each file to call diferent php file for different purpose, I need to make it common. I am explaining one example below.
logincontroller.js:
var loginAdmin=angular.module('Takeme');
loginAdmin.controller('loginController',function($scope,$http,$location,$window,inputField){
$http({
method: 'POST',
url: "php/Login/verify.php",
data: userData,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).then(function successCallback(response){
},function errorCallback(response) {
});
}
I have one common route.js file which is common for all controller and given below.
route.js:
var Admin=angular.module('Takeme',['ui.router', '720kb.datepicker','ngMessages','ngCapsLock','ui.bootstrap','ngFileUpload','angularUtils.directives.dirPagination']);
Admin.run(function($rootScope, $state) {
$rootScope.$state = $state;
});
Admin.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('/',{
url: '/',
templateUrl: 'view/login.html',
controller: 'loginController'
})
})
Admin.factory('inputField',function($timeout,$window){
return{
borderColor:function(id){
$timeout(function() {
var element = $window.document.getElementById(id);
if(element){
element.focus();
element.style.borderColor = "red";
}
});
},
clearBorderColor:function(id){
$timeout(function() {
var element = $window.document.getElementById(id);
if(element){
element.style.borderColor = "#cccccc";
}
});
}
};
});
Here I need to that $http service to call the php file common for which in every controller I will call that $http repeatedly. I need to pass only the parameters for $http service and return the response.
create a factory/service
angular.module('myApp').factory('DataService', DataService);
DataService.$inject = ['$http', '$q'];
function DataService($http, $q) {
return {
getData: getData,
}
function getData(userData) {
var deferred = $q.defer();
$http({
method: 'POST',
url: "php/Login/verify.php",
data: userData,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(function(response) {
deferred.resolve(response.data);
},
function(error) {
deferred.reject(error.data);
});
return deferred.promise;
};
}
then use this factory whenever you need in a controller
angular.module('myApp')
.controller('MyController', ['$scope', 'DataService',
function($scope, DataService ) {
$scope.getMyData = function() {
var data = {};
DataService.getData(data)
.then(function(response) {
}, function(error) {
});
};
}
]);
I have created this service.
and using **enrollments.getProperty();**this statement to call this service but it's not working I'm new to angular-JS please let me know where I making the mistake.
var helloAjaxApp = angular.module("myApp", []);
helloAjaxApp.service('enrollments', [ '$scope', '$http', function ($scope, $http) {
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded; charset=utf-8";
var enrollments = null;
enrollment();
$scope.enrollment=function () {
$http({
url : 'enrollments',
method : "GET"
}).then(function(response) {
enrollments = response.data;
alert("enrollments");
});
};
return {
getProperty: function () {
return enrollments;
},
setProperty: function(value) {
enrollments = value;
}
};
}]);
use angular.module()
(function () {
'use strict';
angular.module("helloAjaxApp")
.service('enrollments', ['$scope', '$http', function ($scope, $http) {
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded; charset=utf-8";
var enrollments = null;
enrollment();
$scope.enrollment = function () {
$http({
url: 'enrollments',
method: "GET"
}).then(function (response) {
enrollments = response.data;
alert("enrollments");
});
};
return {
getProperty: function () {
return enrollments;
},
setProperty: function (value) {
enrollments = value;
}
};
}]);
});
Angular has 2 ways of defining a service: service and factory.
here you can see the difference: https://blog.thoughtram.io/angular/2015/07/07/service-vs-factory-once-and-for-all.html
The basic difference is that service is like a constructor, so you don't return an object from it but define the properties using this keyword:
this.getProperty = function () {
return enrollments;
}
When using the factory method, is expects an object to be returned with the exposed properties/functions.
You are using the factory syntax, so just change the definition to use factory:
helloAjaxApp.factory('enrollments', [ '$scope', '$http', function ($scope, $http)
You should go for a proper service structure like so:
var helloAjaxApp = angular.module("myApp", []);
function EnrollmentService($scope, $http) {
let _this = this;
this.enrollments = null;
this.getEnrollments = function() {
return $http({
url: 'enrollments',
method: 'GET'
}).then(function(response) {
_this.enrollments = response.data;
return _this.enrollments;
})
};
this.setEnrollments = function(enrollments) {
_this.enrollments = enrollments;
}
}
helloAjaxApp.service('enrollments', ['$scope', '$http', EnrollmentService]);
Then, use the service anywhere else:
enrollmentService
.getEnrollments()
.then(function(enrollments) {
// You can use the data here.
console.log(enrollments);
});
The controller code
LoginService is service name you have to pass as a parameter to controller
var loginModule = angular.module('LoginModule',[]);
loginModule.controller('logincontroller', ['$rootScope','$scope','$http','$window','$cookieStore',
'LoginService',logincontrollerFun ]);
function logincontrollerFun($rootScope, $scope, $http, $window,$cookieStore, LoginService,RememberService) {
$scope.loginTest = function() {
LoginService.UserStatus($scope, function(resp) {
console.log("response of login controller ::: ", resp);
///write ur code
});
}
}
service code
var loginModule = angular.module('LoginModule')
loginModule.factory("LoginService",[ '$http', LoginServiceFun ])
function LoginServiceFun($http) {
function UserStatus($scope,callback){
var targetRequestPath='./url';
var targetRequestParamsREQ={'email':$scope.email,'password':$scope.passWord};
return $http({
method: 'POST',
url: targetRequestPath,
headers: {'Content-Type': 'application/json'},
data: targetRequestParamsREQ
}).then(function (response){
console.log('Response Data : ', response.data);
callback( response.data );
})
}
return {
UserStatus:UserStatus
}
}
Everytime when I make View redirect (I use href to do so) I can see that AngularJS runs GetAjaxData1, GetAjaxData2.
In the other words: instead of the single initial request to the server, I do it everytime when I make View redirection. What is wrong?
Here is my AngularJS code:
myApp.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/', {
controller: 'UController',
templateUrl: '/Partial/View1.html'
}).when('/View2', {
controller: 'UController',
templateUrl: '/Partial/View2.html'
}).otherwise({redirectTo: '/View3'});
}]).factory('uFactory', function () {
var factory = {};
data1 = [];
data2 = [];
factory.getAjaxData1 = function () {
$.ajax({
url: url,
type: 'GET',
contentType: "application/json",
async: false,
success: function (result) {
data1 = result;
}
});
return data1;
};
factory.getAjaxData2 = function () {
$.ajax({
url: url,
type: 'GET',
contentType: "application/json",
async: false,
success: function (result) {
data2 = result;
}
});
return data2;
}
};
var controllers = {};
controllers.uController = function ($scope, $location, uFactory) {
$scope.data1 = uFactory.getAjaxData1();
$scope.data2 = uFactory.getAjaxData2();
};
You definitely have to read about $http and ng-resource library and
try more angular way in your application and you also should
understand that ajax request is always asynchronous, and try to
understand promise pattern.
Technically - what you need is a caching - no matter how you are going to implement this - you need to make a single call to the API and the to cache variable.
I don't like idea of usage $.ajax, but it can look like this:
angular.module('myApp').config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/', {
controller: 'UController',
templateUrl: '/Partial/View1.html'
}).when('/View2', {
controller: 'UController',
templateUrl: '/Partial/View2.html'
}).otherwise({redirectTo: '/View3'});
}]).factory('uFactory', function () {
return {
getFirstPromise: function () {
if (!this.$$firstPromise) {
this.$$firstPromise = $.ajax({
url: url,
type: 'GET',
contentType: "application/json"
}).then(function (data) {
window.data1 = data;
});
}
return this.$$firstPromise;
}
... //some other code
}
});
var controllers = {
uController: function ($scope, $location, uFactory) {
uFactory.getFirstPromise().then(function (data) {
$scope.data1 = data;
});
// same for other data - and don't try to make ajax requests synhronous ;-)
}
};
Controllers are not singletons. So your "UController" is created everytime your view changes. I assume that the factory is used inside this controller. See: What is the lifecycle of an AngularJS Controller?
I've often had a problem where I had a scope variable set up in a parent controller, and the child controller calls this scope variable. However, it calls it before the function has been able to set the scope element, causing it to return undefined. Example:
Parent Controller:
module.controller('parent', '$scope', '$http', function ($scope, $http) {
$scope.init = function(profileID, profileViewStatus) {
//Initiiaze user properities
$http.get(requestUserInformationGetURL + profileID)
.success(function(profile) {
$scope.profile = profile;
$scope.userID = profile.user_id;
$scope.username = profile.username;
console.log($scope.userID);
})
.error(function() {
exit();
});
}
Child Controller:
module.controller('child', function($scope, $http, fetchInfo) {
console.log($scope.userID);
//Fetch the HTTP POST data for the user profile
var promise = $http({
method: "post",
url: fetchInfo,
data: {
user_id: $scope.userID //From the parent controller
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
promise.then(function(successResponse) {
//Populate the scope, log the data
console.log(successResponse);
$scope.data = successResponse.data;
}, function(error) {
alert(error);
});
HTML:
<div ng-controller="parent" init="init('<?php $user_id;?>')">
<div ng-controller="child">
</div>
</div>
What often happens is that the userID will be reported back as undefined in the child controller, but then right after, it will be reported back as defined in the parent controller. Obviously, the child controller using the $scope.userID is being called before the init function in the parent controller is complete. How do I force AngularJS to wait in the child controller until the init function is complete? I've tried something like:
if (!$scope.userID) {
$scope.$digest();
}
But it didn't work and I don't think it's the correct syntax. I guess, I don't fully understand the Asycn nature of AngularJS and this occurs multiple times. How do you control the DOM loading elements to solve something like this problem?
Proper way in this case would be to use dedicated service to handle async operations, requests, data caching, etc. But since you don't have service layer yet, I will propose simple Promise-based solution using controller scope promise object.
Check you modified code:
module.controller('parent', ['$scope', '$http', function ($scope, $http) {
$scope.init = function (profileID, profileViewStatus) {
$scope.profilePromise = $http.get(requestUserInformationGetURL + profileID).success(function (profile) {
$scope.profile = profile;
$scope.userID = profile.user_id;
$scope.username = profile.username;
})
.error(exit);
}
}]);
module.controller('child', function($scope, $http, fetchInfo) {
// Fetch the HTTP POST data for the user profile
$scope.profilePromise.then(function() {
return $http({
method: "post",
url: fetchInfo,
data: { user_id: $scope.userID },
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
})
.then(function(successResponse) {
console.log(successResponse);
$scope.data = successResponse.data;
}, function(error) {
alert(error);
});
});
As you can see, parent controller init method is still called, but now it immediately sets scope property profilePromise, which is accessible in child controller.
Child controller uses then method of the parent controller profilePromise object, which guaranties that $http request using $scope.userID will fire after profile is already available.
Generally you would use a route resolve with the UI Router to ensure the work is done before either controller is constructed. Child states automatically have access to the resolves of their parent.
//Router configuration
.state('app.inspections.list', {
url: '',
templateUrl: 'Template/parent',
controller: "Parent as vm",
resolve: {
profile: ['$http', function ($http) {
return $http.get(requestUserInformationGetURL + profileID)
.success(function(profile) {
console.log(profile.userID);
return profile;
})
.error(function() {
exit();
});
}]
}
}).state('parent.child', {
url: 'child',
templateUrl: 'Template/child',
controller: "Child as vm"
})
//parent controller
module.controller('parent', '$scope', 'profile', function ($scope, profile){
$scope.profile = profile;
$scope.userID = profile.user_id;
$scope.username = profile.username;
}
//child controller
module.controller('child', 'profile', function($scope, $http, fetchInfo, profile){
console.log(profile.userID);
//Fetch the HTTP POST data for the user profile
var promise = $http({
method: "post",
url: fetchInfo,
data: {
user_id: profile.userID //From the parent controller
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
promise.then(function(successResponse) {
//Populate the scope, log the data
console.log(successResponse);
$scope.data = successResponse.data;
}, function(error) {
alert(error);
});
you can use promise ($q service) :try using this code:
parent controller :
$scope.init = function(profileID, profileViewStatus) {
var deferred = $q.defer();
$http.get(requestUserInformationGetURL + profileID)
.success(function(profile) {
$scope.profile = profile;
$scope.userID = profile.user_id;
$scope.username = profile.username;
deferred.resolve($scope.userID);
console.log($scope.userID);
})
.error(function() {
deferred.reject('error');
exit();
});
return deferred.promise;
}
Don't call init method in parent contrller.
in child controller:
$scope.init().then(function(userID){
var promise = $http({
method: "post",
url: fetchInfo,
data: {
user_id: userID //From the parent controller
},
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
});
promise.then(function(successResponse) {
//Populate the scope, log the data
console.log(successResponse);
$scope.data = successResponse.data;
}, function(error) {
alert(error);
});
})
.catch(function(error){
console.log('error');
})
Your problem might be that $.get is being called asynchronously, which is the default behavior. Your init method might actually be called in the order you're expecting but what's happening is:
Parent init is called
$.get is called, but the server's response is non-instantaneous
Child init is called
GET data bounces back from the server
$.get(..).success(function(data){...}); is called to deal with the data
I'd suggest what other people are, using promises to defer execution.
I have defined a custom http service in angular that looks like this:
angular.module('myApp')
.factory('myhttpserv', function ($http) {
var url = "http://my.ip.address/"
var http = {
async: function (webService) {
var promise = $http.get(url + webService, { cache: true }).then(function (response) {
return response.data;
});
return promise;
}
};
return http;
});
And I can access this service in my controller like so:
angular.module('myApp')
.controller('myCtrl', function (myhttpserv) {
var webService = 'getUser?u=3'
myhttpserv.async(webService).then(function (data) {
console.log(data);
})
});
However I now need to streamline this process so that it is ALL contained inside the service with a static url and it simply returns the data. So that I can just call it in the controller like so:
angular.module('myApp')
.controller('myCtrl', function ($scope, myhttpserv) {
console.log(myhttpserv.var1);
console.log(myhttpserv.var2);
etc...
});
I can't seem to tweak the service to get this functionality. Anyone know the correct way to do it?
Option 1 - Use promise API
angular.module('myApp').factory('myhttpserv', function ($http) {
return $http.get('http://my.ip.address/getUser?u=3', { cache: true });
});
Controller:
angular.module('myApp').controller('myCtrl', function ($scope, myhttpserv) {
myhttpserv.then(function(response){
console.log(response.data);
});
});
Option 2 - Using route resolve
angular.module('myApp', ['ngRoute']).config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/myCtrl', {
templateUrl: 'myView.html',
controller: 'myCtrl',
resolve: {
load: function (myhttpserv) {
return myhttpserv;
}
});
}]);
Service:
angular.module('myApp').factory('myhttpserv', function ($http) {
var data = {};
var url = "http://my.ip.address/";
var promise = $http.get(url + 'getUser?u=3', { cache: true }).then(function (response) {
data = response.data;
});
return data;
});
Controller:
angular.module('myApp')
.controller('myCtrl', function ($scope, myhttpserv) {
console.log(myhttpserv.data.var1);
console.log(myhttpserv.data.var1);
etc...
});
Option 3 - Use $interval service
angular.module('myApp').factory('myhttpserv', function ($http) {
var data = {};
var url = "http://my.ip.address/";
var promise = $http.get(url + 'getUser?u=3', { cache: true }).then(function (response) {
data = response.data;
});
return data;
});
Controller:
angular.module('myApp').controller('myCtrl', function ($scope, $interval, myhttpserv) {
$scope.intervalPromise = $interval(function(){
if (Object.keys(myhttpserv.data).length!=0)
{
console.log(myhttpserv.data);
$interval.cancel($scope.intervalPromise);
}
}, 100);
});