Master detail in AngularJS - angularjs

I try to write a small app that get a list from REST API and displays details for each selected item. I was looking for a simple tutorial on how to transfer the selected id from the list view to the detail view, but couldn't figure out. I assume I need to use the Master-detail technique.
Here's the code:
The list view:
<ul>
<li ng-repeat="gadgetDetails in gadgettDetails">
<div>
<p>{{gadgetDetails.type}}</p>
<p>{{gadgetDetails.manufacturer}}</p>
</div>
<hr />
</li>
</ul>
And the detail view
<div>
<p>Go back to Gadgets list</p>
<p>{{gadgetDetails[2].type}}</p>
<p>{{gadgetDetails[2].color}}</p>
<p>{{gadgetDetails[2].manufcturer}}</p>
</div>
So just for the question I've put 2 (the second object in the JSON list that I get from the REST API , but it actually should be gadgetDetails[i].type
but I couldn't figure out how to get the index (for example i) for each item in the list
This the controller:
GadgetListCtrl.controller('gdgtList', function($scope, $http, $filter) {
$http.get('https:.../gadgets.json').
then(function(response) {
$scope.gadgettDetails = response.data;
});
});
So the question is how to display for each item its details by the id.
Thanks

you can achive this by angular ui router params
below is dummy code
in .config block
$stateProvider
.state('gadgets', {
url: "/gadgets/:id",
templateUrl: 'gadgetDetail.html',
controller: 'gadgetController',
controllerAs: 'vm',
params: {
id: null
}
});
and in controller file, you can access the id as below
.controller('GadgetController', function($state, $stateParams) {
var selectedID = $state.params.id;
//alternatively you can get using $stateParams service
// $stateParams.id
if(selectedID) {
// get detail of gadget
}
});

Related

multistep form and sharing data with angular-ui-router

I am trying to create a multistep form and am having trouble sharing data between views/states. I'm not sure that the way I'm even going about this is accurate as I am new to angular-ui-router. Here are my routes:
.state('tab.newEventCategory', {
url: '/activities/new-event-category',
views: {
'tab-patient': {
templateUrl: 'templates/new-event-category.html',
controller: 'ActivityDashboardCtrl'
}
}
})
.state('tab.newEventSubCategory', {
url: '/activities/new-event-sub-category',
views: {
'tab-patient': {
templateUrl: 'templates/new-event-sub-category.html'
}
}
})
I am trying to use the routes above so that once someone chooses a category, they then go to a page where they choose a subcategory. Here is the new-event-category page:
<div ng-repeat="event_category in event_categories" class="padding">
<a class="button button-block button-positive button-large" ng-click="moveToEventSubCategory(event_category)">
{{event_category}}
</a>
</div>
and here is the controller for the page:
.controller('ActivityDashboardCtrl', function($scope, $stateParams, EventCategory, $state) {
$scope.formData = {};
$scope.event_categories = EventCategory.query();
$scope.moveToEventSubCategory = function(event_category){
$scope.formData.category = event_category;
$state.go('tab.newEventSubCategory');
}
})
My issue is that now I want the newEventSubCategory state to have access to the same formData object so it can add subcategories. There will be more pages to this multistep form after this and I want them to all have access to the same formData variable. How do I do this?
If you want to communicate between controllers/states you best option it what #ronnie mentioned; creating a service or factory.
Have a look at this if you want to work out what services are and how to user them: AngularJS Step-by-Step: Services

AngularJs - Unable to pass object using routeProvider

I load some data from the server, and then update the view using ng-repeat. The user has the ability to edit the data in another page. Now, is the part where I'm a bit confused. I can pass some parameters using $routeProvided combined with $routeParams, lets say id and fetch the data again from the server depending on that id. I believe there's a better way, something like passing the whole object to the next controller, rather than conducting another call the server. That's what I've got working right now:
app.config(function($routeProvider) {
$routeProvider
.when('/editPost/:postId/:author', {
templateUrl: 'editPost.html',
controller: 'editPostCtrl'
});
});
app.controller('editPostCtrl', function($scope, $routeParams) {
console.log($routeParams.author + ", " + $routeParams.postId);
});
Now, I cant extract the object with the following code:
HTML:
<div ng-repeat="post in posts">
<button class="btn" ng-click="editPost(post)">Edit</button>
</div>
JS:
app.config(function($routeProvider) {
$routeProvider
.when('/editPost/:post', {
templateUrl : 'editPost.html',
controller : 'editPostCtrl'
});
});
app.controller('editPostCtrl', function($scope, $routeParams) {
console.log($routeParams.post); //results in [object object]
});
Is there a better way for achieving this?

Binding to data when changing the URL

I am building an application that uses ui-router. On my /teams route I have a form where a user can add a team name which then pushes the name to my MongoDB and binds to the view and displays the team name with several options, one of those being a button that links to a page where more specific information can be added for the team. I have the routing working on this and the url appears like /#/teams/oklahoma or /#/teams/washington for example. Here is what my routing looks like:
app.config(
['$stateProvider','$urlRouterProvider',
function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('/');
.state('teams', {
url: '/teams',
templateUrl: './templates/main/league.html',
controller: 'leagueCtrl'
})
.state('teams/:title', {
url: '/teams/:title',
templateUrl: './templates/main/team.html',
controller: 'teamCtrl'
})
Here is my link to the /teams/:title route:
<a href="#subjects/{{ team.title | lowercase }}">
<button ng-click="viewTeam(team)" class="team-button">View</button>
</a>
Currently I do not have anything in my viewTeam() function. My question is how do I bind to my {{ team.title }} and other related information in the new view with the new URL? I know a factory must be somehow involved and I have tried implementing the solution described at http://onehungrymind.com/angularjs-communicating-between-controllers/ without success. Any additional guidance would be very much appreciated.
The URL should probably contain the team ID. I'm going to assume your 'teams' array is loaded using $http from some backend API.
app.config(
['$stateProvider','$urlRouterProvider',
function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('/');
.state('teams', {
url: '/teams',
// the `teams` state will wait to load until $http.get() call is completed.
// this resolve declaration will provide the resulting teams array as an injectable 'teams' object.
resolve: { teams: function($http) { return $http.get("/teams.json"); },
templateUrl: './templates/main/league.html',
// This simplified controller injects the 'teams' resolve and simply sticks the list of teams on the scope to ng-repeat etc.
controller: function($scope, teams) { $scope.teams = teams; }
})
// This is a nested state, called `teams.team`. It requires a `teamId` parameter.
// The parameter can be provided by a URL: http://localhost/app#/teams/9237594827
// The parameter can be provided by $state.go: $state.go('teams.team', { teamId: 9237594827 });
// The parameter can be provided by uiSref: <a ui-sref="teams.team({ teamId: repeatedTeam.id })">{{repeatedTeam.title}}</a>
.state('teams.team', {
// `teams.team` state declares a `teamId` state parameter in the URL
url: '/teams/:teamId',
// This resolve function uses $stateParams to locate the correct team from the list.
// `team` will be made available for injection
resolve: {
team: function($stateParams, teams) {
// Find the correct team from the `teams` array, by ID.
return teams.filter(function(team) { return team.id === $stateParams.teamId; })[0];
}
},
templateUrl: './templates/main/team.html',
// Inject the `team` resolve and put it on $scope
controller: function($scope, team) { $scope.team = team; }
})
league.html:
<ul>
<li ng-repeat="team in teams">
<a ui-sref="teams.team({ teamId: team.id })">{{team.title}}</a>
</li>
</ul>

AngularJS and Firebase not showing the $id

I am trying to do an application that tracks attendees' approval of a speech or similar. I am facing a challenge which holds me off for now several hours.
Here is the js file
angular.module('speechAssessment', ['ngRoute', 'firebase'])
.value('fbURL', 'https://XXXX.firebaseio.com/')
.factory('Attendees', function($firebase, fbURL) {
return $firebase(new Firebase(fbURL));
})
.config(function($routeProvider) {
$routeProvider
.when('/', {
controller:'ListCtrl',
templateUrl:'partials/list1.html'
})
.otherwise({
redirectTo:'/'
});
})
.controller('ListCtrl', function($scope, Attendees) {
$scope.attendees = Attendees;
});
As you can see, I stripped the app to the bare minimum. I am getting data from Firebase and bring it into the $scope.attendees.
the html looks like
<div class="row">
<ul>
<li ng-repeat="attendee in attendees | orderByPriority">
<p>{{attendee.name}}:{{attendee.score}}:{{attendee.$id}}</p>
</li>
</ul>
</div>
I list all attendees and list some attributes, among them the $id from Firebase
So, a typical row looks like
roestigraben:-45:-JTI2DALNZXxltukIHcY
Now the application shows correct results until I remove the | orderByPriority filter. Doing so, the application runs but does not show the $id any longer. I cannot understand why this Filter has anything to do with the listing of the $id.
Can somebody shade some light on this for me, please. Really appreciated.

Conditional partials in Angular.js

Angular novice here. I'm trying to wrap my head around the right way to accomplish a basic template issue.
I have a header, which should read “click here to log in” when the user is not logged in, and “Welcome, Dudefellah” (and associated Settings links and whatnot) when a user is logged in.
I've written a Service that is able to return a JSON bundle including a login state and username, but I don't know what “The Angular Way” to express: “if(auth.loggedin), output partials/header.html; else output partials/header_login.html”.
I’m unclear as to whether this logic would belong in the controller, or some kind of “auth” model, or even in the view (that can't be right, right?). Any assistance would be greatly appreciated.
Within the controller once the login state is fetched create a scope variable headerTemplate and assign the name of the template depending on the login state
function MyCtrl($scope, loginService) {
$scope.auth = loginService.getLoginState();
$scope.headerTemplate = $scope.auth ? 'partials/header.html' : 'partials/header_login.html';
}
In in your markup
<div ng-include src="headerTemplate"></div>
There's a sample angular application called angular-app that does this really well. They have a security service, then a toolbar partial and directive that shows things depending on the state.
https://github.com/angular-app/angular-app/tree/master/client/src/common/security
from angular-app:
src/common/security/login/toolbar.tpl.html:
<ul class="nav pull-right">
<li class="divider-vertical"></li>
<li ng-show="isAuthenticated()">
{{currentUser.firstName}} {{currentUser.lastName}}
</li>
<li ng-show="isAuthenticated()" class="logout">
<form class="navbar-form">
<button class="btn logout" ng-click="logout()">Log out</button>
</form>
</li>
<li ng-hide="isAuthenticated()" class="login">
<form class="navbar-form">
<button class="btn login" ng-click="login()">Log in</button>
</form>
</li>
</ul>
src/common/security/login/toolbar.js:
angular.module('security.login.toolbar', [])
// The loginToolbar directive is a reusable widget that can show login or logout buttons
// and information the current authenticated user
.directive('loginToolbar', ['security', function(security) {
var directive = {
templateUrl: 'security/login/toolbar.tpl.html',
restrict: 'E',
replace: true,
scope: true,
link: function($scope, $element, $attrs, $controller) {
$scope.isAuthenticated = security.isAuthenticated;
$scope.login = security.showLogin;
$scope.logout = security.logout;
$scope.$watch(function() {
return security.currentUser;
}, function(currentUser) {
$scope.currentUser = currentUser;
});
}
};
return directive;
}]);
You could also use ui-router which does wonders for conditional routing and for good infrastructure in general. You'll need to define two states:
myapp.config(function($stateProvider, $urlRouterProvider){
...
// Now set up the states
$stateProvider
.state('login', {
parent: account,
url: "/login",
templateUrl: "partials/header_login.html"
})
.state('auth', {
parent: account,
url: "/authorized",
templateUrl: "partials/header.html"
})
})
when you are back from your query, change state by $state.transitionTo('login') or ('auth') and the router will load the right template for you (and also the URL). in general its much better to use a good router as the basis of your app and not give ad-hoc solutions per each case. you could also read a page (I wrote) about it here

Resources