I want to know how to dynamically change an $http call so that the $http request URL differs based on the element that is clicked in an ng-repeat list. But I'm stuck.
Currently, I have an ng-repeat set up on my index page:
<div ng-repeat="team in nt.getStandings">
<h2>{{team.team_name}}</h2>
<p>Team ID = {{team.team_id}}</p>
</div>
The variable getStandings is taken from an API via an $http call. Like so:
In StandingsService
return $http.get(
'http://api.com/standings/1005?Authorization=xxxx'
)
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
And then StandingsService is attached to the getStandings variable in my controller.
"1005" is a property which calls a specific array, in this case a particular sporting competition, from an array of competitions.
So, on my index page I'm using ng-repeat to list all teams within that competition.
As you can see on the html above, I have linked each team so that it dynamically generates a URL which appends the team_id to the end, which using $routeParams I define as the variable whichTeam.
Team Details Page
<h1>Dynamic Team ID = {{whichTeam}}</h1>
This works fine, the team ID is generated dynamically according the team that is clicked.
Just like 'StandingsService' above, I have another service called 'TeamService' which makes an $http request to pull team data. Currently though it is set up statically to make a call to one individual team - I want to make the service take in the whichTeam variable so that the call changes depending on which team was clicked.
This is the static team $http request (I've broken the URL apart and concatenated to make it clearer):
return $http.get(
'http://api.com/team/' + '16110' + '?Authorization=xxxx'
)
I want the 16110 part, which refers to ONE team, to be a the whichTeam variable, allowing it to pull in the correct individual team data, but I don't know how to write this (or indeed if it's possible).
I hope I've been clear - happy to clarify further if needed. Thanks in advance.
Make a factory:
app.factory("DataService", ["$http", function($http) {
return {
getTeamDetailsById: function(teamId) {
return $http.get('path/to/api' + teamId + '?Auth=xxxx')
}
};
}]);
Use it in a controller:
app.controller("MainCtrl", ["$scope", "DataService", function($scope, DataService) {
$scope.teamDetails = {};
$scope.getTeamDetailsById = function(event, teamId) {
//prevent click navigation
event.preventDefault();
//call factory service
DataService.getTeamDetailsById(teamId).then(function(response) {
//success callback
$scope.teamDetails = response.data;
}, function(response) {
//an error has occurred
});
}
}]);
In the ng-repeat element:
<div ng-repeat="team in teams">
<a href ng-click="getTeamDetailsById($event, team.team_id)">{{team.team_name}}</a>
</div>
The above assumes you have only one state and are storing in only one controller. If you want to use different states usving $stateProvider, then you'd have to use parameters, by making use of ui-sref and passing in team Id.
If indeed you are using $states and parameters, do this:
<a href ng-click="goToState($event, team.team_id)">{{ team.team_name }}</a>
$scope.goToState = function(e, teamId) {
$state.go("teamDetailsState", { "teamId": teamId });
}
Related
I am using Angularjs for my application and I would like to transfer the data between the modules, tried all the ways, but the data is not getting passed. Please have a look at my code here.
I have a page called departments in frontapp module, while clicking on particular department, I want to pass the department Id to departmentapp module where each department will have its own page.
<h5>{{school.schoolName}}</h5>
<ul data-ng-repeat="department in school.departments">
<li data-ng-click="getdepartmentBydepartmentId(department.departmentId);setDepartmentId(department.departmentId)">
{{department.departName}}
</li>
The code of Controller
$scope.getdepartmentBydepartmentId = function(departmentId){
SchoolService.getdepartmentBydepartmentId(departmentId).then(function(response){
$scope.department= response.data;
});
}
$scope.getDepartmentId=function(){
SchoolService.getDepartmentId().then(function(response){
$scope.departmentId = response.data;
});
}
$scope.setDepartmentId=function(departmentId)
{
//Some authentication code...
alert(departmentId);
SchoolService.setDepartmentId(departmentId);
alert(SchoolService.getDepartmentId());
//Here I want to pass the username to homectrl.js
window.location.href="./department"
}
The code in services js file
obj.getDepartmentId=function(){
return departmentIDSchool;
};
obj.setDepartmentId=function(departmentID){
// var departmentID = null;
departmentIDSchool = departmentID;
};
obj.getdepartmentBydepartmentId=function(departmentId){
return $http.post('getdepartmentBydepartmentId?departmentId='+departmentId);
};
In departmentapp module - departmentcontroller.js
app.controller("SchoolController", SchoolController);
app.service("SchoolService",SchoolService);
angular.module("frontApp").SchoolService.getDepartmentId().then(function(response){
$scope.departmentId = response.data;
alert($scope.departmentId);
});
But here departmentId I am not getting. After going through many questions at stack overflow, I come to know that in service layer we need to have getter and setter, but even after placing that it is not working. Can some one help me here?
You can pass a variable like that easily in the router
$routeProvider.when('/:primaryNav/:secondaryNav', {
templateUrl: 'resources/angular/templates/nav/'+$routeParams.primaryNav+'/'+$routeParams.secondaryNav+'.html'
});
See the $routeParams in templateUrl, you can also inject it into your controller to get the params.
So I've defined a custom section in Umbraco 7:
namespace NZ_Realty_Ltd.CRM
{
[Application("crm", "CRM", "trayuser", 8)]
public class CrmSection : IApplication { }
}
It shows up, no worries here. But it needs a view and controller. So I made a start on the controller:
angular.module("umbraco").controller("CrmController",
function ($scope, $http) {
$http.get('backoffice/crm/ContactApi/GetAll').success(function (data) {
$scope.contacts = data;
});
});
Again, no problem. My data is being read from a C# CRUD api and being sent back to the view. But I want to paginate these results. So I'm trying to use this custom directive to do it: https://github.com/michaelbromley/angularUtils/tree/master/src/directives/pagination
Here's my html view:
<div ng-controller="CrmController">
<umb-pane>
<p>Page {{currentPage}} / {{totalPages}}</p>
<p>Showing {{pageSize}} items per page:</p>
<ul class="contacts">
<li dir-paginate="contact in contacts | itemsPerPage: 10">
<span>{{contact.name}}</span>
<p>{{contact.bio}}</p>
</li>
</ul>
<dir-pagination-controls></dir-pagination-controls>
</umb-pane>
</div>
The problem is none of these expressions are showing up (they are all blank). I've missed the step of how to include the pagination module. Actually I've been stuck on it for hours. I've tried everything from:
angular.module("umbraco", ['angularUtils.directives.dirPagination']).controller("CrmController",
function ($scope, $http) {
$http.get('backoffice/crm/ContactApi/GetAll').success(function (data) {
$scope.contacts = data;
});
});
... To just including the directive javascript file from <script> tags. But I really have no idea what I'm doing and don't understand the module syntax well enough (I've read through the pagination demo so many times but it just seems SO different to working with the umbraco angularjs app). I saw in the docs that including the second parameter means you're making a new module. But what is the relevance of the information inside the [] on the second parameter? And why would I be creating a new module? Can't I just include the existing directive?
EDIT: This is the closest in my mind to what should work. But I get no contacts listed and no pagination controls showing. My idea with it is to load the pagination module (and thus directive), and then create my controller as normal to avoid conflicts and load order stuff, but also adding default values in the controller as in the example here: http://plnkr.co/edit/Wtkv71LIqUR4OhzhgpqL?p=preview
angular.module("angularUtils.directives.dirPagination");
angular.module("umbraco").controller("CrmController",
function ($scope, $http) {
$http.get('backoffice/crm/ContactApi/GetAll').success(function (data) {
$scope.contacts = data;
$scope.currentPage = 1;
$scope.pageSize = 10;
});
});
You could add this before your controller starts:
app.requires.push('angularUtils.directives.dirPagination');
Read more at:
https://our.umbraco.org/forum/umbraco-7/developing-umbraco-7-packages/47905-Including-an-angular-module
I have some parameters in the $rootScope as specified below:
myApp.factory('itemService', function($http) {
return $http.get('/items');
});
myApp.run(function($rootScope, itemService) {
itemService.success(function(response) {
$rootScope.items = response;
});
});
myApp.controller('displayCtrl', function($rootScope, $scope) {
$scope.items = $rootScope.items;
});
When I run the above code, I get this error from firebug
TypeError: $rootScope.items is undefined. I really do not know what is happening.
Here is a small addition. items is an array with a list of objects like this:
items = [
{'name': 'spoon', 'price': 200},
{'name': 'table', 'price': 400},
{'name': 'shoe', 'price': 250}
];
I wish to make items available constantly in my app such that I can display each item on the item list (items) without making another request to the server. I intend to achieve this by simply displaying an item using $scope.item = items[$routeParams.id] each time I need to display an item.
I look forward to implement this using either a function attached to ng-click or the normal #/route/:param mechanism.
Thanks
TypeError: $object.property is undefined is usually because a request to a reference of an object is made before that specific object (or its property) has been set. $http requests are asynchroneous by nature so other processes do not get blocked. It should be obvious that trying to make requests synchroneous could cause a major issue for people with very slow connections.
Apart from that, polluting the $rootScope is generally a bad idea. You can find a topic about global variables on the following link so that you investigate why the $rootScope is not such a good place.
Having said all that, it seems to me that you didn't want to make multiple requests to retrieve the same data. If so, you can use the cache option for $http.get methods.
e.g:
myApp.factory('itemService', function($http, $q) {
return {
get: function() {
return $http({
url: 'items.json',
cache: true //keep the result in memory
});
}
};
})
myApp.controller('aCtrl', function(itemService) {
var self = this;
itemService.get().success(function(data) {
self.items = data;
});
});
myApp.controller('bCtrl', function(itemService) {
var self = this;
itemService.get().success(function(data) {
self.items = data;
});
});
This will make sure the information gets requested once and put into a cache. The data is accessible in different places.
<div ng-controller="aCtrl as a">
{{a.items}}
</div>
<div ng-controller="bCtrl as b">
{{b.items}}
</div>
This leaves me with another 'good' practice: the usage of the controllerAs syntax. Which provides a way to use namespaces in AngularJS.
Ofcourse, these are just tips and you should always consider the requirements!
You run asynchronious method at run block :
itemService.success(function(response){
$rootScope.items = response;
});
But initialization goes on, so probably you access $rootScope.items before itemService succeed (or it fails, and you didnt predict such situation). I suggest you to do this (if you want to follow $rootScope convension.. which is bad by the way) :
$rootScope.items = [];
itemService.success(function(response){
$rootScope.items = response;
});
You are setting items in the callback of an asynchronous process, so you are trying to access items on the $rootScope before its actually set.
If you are trying to initialize items when the controller is loaded, then there are other ways to do that such as using the resolve block of a route or manually calling the $http.get on the factory when the controller loads.
Finally, I was able to come up with a solution. I realized that the problem was to have $rootScope.items available in displayCtrl at the same time it loads. But $rootScope.items is available in my view when my html page loads.
So I simply passed the item id as a parameter and obtained it using $routeParams as follows
myApp.controller('displayCtrl', function($routeParams, $scope) {
$scope.item_id = $routeParams.id; //given that the route looks like '/item/:id'
});
Then in my HTML file this what I did
<div ng-bind="items[item_id].name"></div>
<div ng-bind="items[item_id].price"></div>
This actual solved my problem.
Is there a way to reinitialize a controller that is currently active ?
This would help me with transitioning from page to page without adding much additional workaround code.
For example:
<div ng-controller='Blah as ex'>
{{ex.name}}
</div>
and in the controller Blah's initialization function, the name would be retrieved from a service:
this.name = someService.name;
So for the example above, I'd like to have a button which would reinitialize my Blah controller.
edit: This is only a basic example.
I'm using the browser's 'state' in order to restore 'back' and 'forward' data in my controllers.
There are a few cases so I'm trying to simplify its process (which currently works, but is not as 'pretty')
Would something like this be a possible solution? Using route.reload to reload your page?
myapp.Controller('SampleController', function($location, $route) {
$scope.navTo = function(url) {
if ($location.path() === url) {
$route.reload();
} else {
$location.path(url);
}
}
});
I'm just starting to play with angularJS, so maybe I'm asking something easy to do, but I can't find the way to do it.
The situation is the following: I have a list that's populated by an ng-repeat taking the values from a scoped controller variable. This variable is loaded on page load by an jsonp call, and this works fine.
The problem comes when I need to reload this list based on another select. For example, if a select 'day' value in the select I need to show some values and when I select 'week' I need to show others (also loaded via ajax).
What I've tried is to have a service that loads the data and returns it, and in the controller have two methods, one for the first load and another for the second one that does $scope.apply with the variable. I then call this second method on select value change (I've done it with jquery to simplify it until I can fix this).
This is part of my HTML
<div x-ng-controller='LeaderboardCtrl'>
<select id='leaderboard-select'>
<option value='day'>day</option>
<option value='week'>week</option>
<option value='month'>month</option>
</select>
<div x-ng-repeat='p in leaderboard'>
<p>{{p}}</p>
</div>
</div>
And this is part of the code that affects this functionality
var lead = angular.module("lead",[]);
function LeaderboardCtrl($scope,$attrs,$http,jtlanService) {
$scope.leaderboard = [];
$scope.period = 'day';
var data = {
period:$scope.period
};
$scope.loadLeaderboard = function(){
myService.loadLeaderboard(data).then(function(leaderboard) {
$scope.leaderboard = [];
$scope.leaderboard.push.apply($scope.leaderboard,leaderboard);
});
}
$scope.reloadLeaderboard = function() {
myService.loadLeaderboard(data).then(function(leaderboard) {
$scope.$apply(function() {
$scope.leaderboard = [];
$scope.leaderboard.push.apply($scope.leaderboard,leaderboard);
});
});
}
$scope.loadLeaderboard()
}
lead.service("myService",["$http", function($http) {
var myService = {
loadLeaderboard : function(data) {
var promise = $http.jsonp("/widget/leaderboardJSONP?callback=JSON_CALLBACK&_="+new Date(),{
params:data,
cache:false,
ajaxOptions: { cache: false }
}).then(function(response) {
return response.data;
});
return promise;
}
};
return myService;
}]);
$("#leaderboard-select").change(function(){
scope.period = $("#leaderboard-select").val();
scope.reloadLeaderboard();
});
Here's a fiddle with the code: http://jsfiddle.net/WFGqN/3/
Your fiddle is riddled with issues:
There's no ng-app in your mark-up
You need to change the second Framework Extensions dropdown to one of the "No wrap" options
Your service needs to be defined above your controller
Your controller is referencing "jtlanService" but you've defined "myService"
Your $http.jsonp call isn't going to work as is, but you could use can use the echo service (see Ajax Requests on the left side) to emulate requests
You can't and shouldn't be using jQuery events to call Angular controllers. You should use ng-change and not $().change (and even if you were using jQuery for event binding, you should be using $().on('change')).
You didn't need to use $scope.$apply in your loadLeaderboard function, since when you're calling it, you were already inside of of an $apply call.
There's no need for 2 load+reload leaderboard methods.
And after all that, you don't actually need jQuery.
Here's a fiddle that fixes things up and I think gets you what you want: http://jsfiddle.net/WFGqN/5/. You'll of course need to fix the service on your end, but you get the idea.
I recommend reading this SO answer: "Thinking in AngularJS" if I have a jQuery background?