Passing a variable from a controller into a route param - angularjs

....
.state('books', {
url: '/book/chapter/:chap',
templateUrl: "views/chapter.html",
params: { chap: .........}
})
Hi!
I have a variable in a specific controller and I want to pass it's value into a param for routing. Eventually I want to change the value of that variable so that I can create new urls using this same route.
I'm using ui-router, as you may have noticed.
I'm also curious on how would you solve the following problem:
basically I want to open a specific chapter of a book, let's say chapter 5. Then I want to display at the left of the page a link for each remaining chapter, that's why I want to change the value of the variable. How would you solve this using ng-repeat?
I'm thinking of using getArticle (as shown below) to get a chapter number and then ng-repeat the remaining chapters with ng-repeat? Ideas?
angular
.module('BookLibrary')
.controller("ChapterController", ["$scope","stateParams", "ChapterControllerService", function($scope, $stateParams, ChapterControllerService){
$scope.chapterList = ChapterControllerService.chapters;
$scope.getArticle = chapterList[0].chapter;
}]);
chapterList looks like this:
chapterList = [
{
chapter: "1",
content: "Chapter 1 goes here"
},
{
chapter: "2",
content: "Chapter 2 goes here"
},
{
chapter: "3",
content: "Chapter 3 goes here"
}
];

There are multiple questions here so to start with your state parameters. In the state params you can declare default values for params in a state like so.
.state('books', {
url: '/book/chapter/:chap',
templateUrl: "views/chapter.html",
params: { chap: null}
})
This would default the value to null. Perhaps you always want to default to chapter 1? If that was the case you can use params: {chap: '1'} (since you are using strings).
To pass a value to the state there are multiple ways to do it. Assuming you are using ui-sref you can hand parameter values right in the link.
ui-sref="books({ chap: 3 })"
However you want to have a list of links from an object using ng-repeat. So you could do something like this
<ul>
<li ng-repeat="chapter in chapterList">
<a ui-sref="books({chap: chapter.chapter})">{{chapter.chapter}}</a>
</li>
</ul>
You've included $stateParams in your controller already so you just need to grab the parameter from it like so
angular
.module('BookLibrary')
.controller("ChapterController", ["$scope","$stateParams",
"ChapterControllerService", function($scope, $stateParams,
ChapterControllerService){
$scope.currentChapter = $stateParams.chap;
$scope.chapterList = ChapterControllerService.chapters;
$scope.getArticle = chapterList[0].chapter;
}]);

Related

Using a variable in ng-repeat and passing it to a controller

I have created an AngularJS app that contains two columns: one for a menu and a second for content (each link in the menu links to). The content and menu is in a table in DynamoDB that I am scanning with a Lambda function. The output of this function is being consumed as a JSON response with the following structure:
{
"body": [{
"course-content": "RL front matter",
"course-video": "https://123-course-videos.s3.amazonaws.com/vid_1.mp4",
"course-id": "rcl",
"course-title": "sml",
"course-lesson": "Lesson One"
}, {
"course-content": "RL2 front matter",
"course-video": "https://123-course-videos.s3.amazonaws.com/vid_2.mp4",
"course-id": "rcl2",
"course-title": "sml",
"course-lesson": "Lesson Two"
}, {
"course-content": "RL3 front matter",
"course-video": "https://123-course-videos.s3.amazonaws.com/vid_3.mp4",
"course-id": "rcl3",
"course-title": "sml",
"course-lesson": "Lesson Three"
}]
}
I (with the help of the great folks here) built the following controller that loops through the response and builds the menu:
controller
app.controller('menu', function($scope, $http) {
$http.get('api address').
then(function(response) {
$scope.navi = response.data.body;
$scope.selectCourse = function(course, index, path) {
console.log(path)
$scope.content = response.data.body[index]
console.log($scope.content)
};
});
});
menu built using ng-repeat
<div ng-repeat="nav in navi">
<ul><li>{{ nav['course-lesson'] }}
<button ng-click="selectCourse(nav, $index, '/content/' +
$index)">Select</button>
</li></ul>
</div>
This build the following menu:
Lesson One <button>
Lesson Three <button>
Lesson Two <button>
And I am using a second controller that consumes the content from the same api call:
app.controller('content', function($scope, $http) {
$http.get('api address').
then(function(response) {
$scope.content = response.data.body;
});
});
content is displayed in a route with a simple content.html template as follows:
app.config(function($routeProvider) {
$routeProvider
.when("/", {
templateUrl : "templates/main.html"
})
.when("/content/:id", {
templateUrl : "templates/content.html",
controller : "content"
});
Updated: Here is where I still need help:
How do I pass/use the $index variable in the menu controller to the content controller so the content updates as needed in the right template when I click on each button?
To help better understand the functionality:
Lesson One links to content for lesson one - lesson one content is
displayed in the content template.
List item Lesson Two links to content for lesson two - lesson two content is
displayed in the content template.
List item Lesson Three links to content for lesson three - lesson three content
is displayed in the content template.
Sorry for the long post, but I wanted to provide enough detail to help clarify any confusion.
To pass data to a controller from an ng-repeat element, use the ng-click directive:
<div class="col-4" ng-controller="menu">
<div ng-repeat="nav in navi">
<ul>
<li>
{{ nav['course-lesson'] }}
<button ng-click="selectCourse(nav, $index)">Select</button>
</li>
</ul>
</div>
Assign the function to scope:
$scope.selectCourse = function(course, index) {
console.log(course, index);
};
For more information, see
AngularJS ng-click Directive API Reference

How to navigate one page to another page with $scope value parameter in data-ui-sref in Angular Js?

I am using angular js for the web application. So I want to navigate one page to another page with some parameter in data-ui-sref. When I use static parameter then it will navigate with parameter.
Example:
<a data-ui-sref="app.admin({startFrom:'param1',endTo:'param2'})">click</a>
Module.js
.state('app.admin', {
url: '/travlers?startFrom&endTo',
data: {
title: 'travelers'
},
params :
{
startFrom: null,
endTo:null
},
views: {
"content#app": {
templateUrl: 'app/admin.html',
controller: 'admin'
}
}
});
If I used static parameter in data-ui-sref then it will work. But If I take from scope value in parameter then it is not working.
When I use scope value in data-ui-sref parameter
example.html
<a data-ui-sref="app.admin({startFrom:'{{dateFrom}}',endTo:'{{dateTo}}'})">click</a>
example.js
angular.module('app.admin').controller('example', function () {
$scope.dateFrom="07-05-17";
$scope.dateTo="07-05-17"
});
When I see in console then scope value is append in data-ui-sref parameter
When I see in console then it is looks like this
<a data-ui-sref="app.systemAdmin.travelers({startFrom:'07-05-17',endTo:'07-05-17'})" class="fa fa-external-link-square" aria-hidden="true" style="font-size:18px;color:#fff" href="#/systemadmin/travlers">click</a>
After click the link then parameter is not going to module.js. URL is form without parameter and parameter(dateFrom,dateTo) is not going in state url.
I have seen one link. But it is for dynamic value Dynamically set the value of ui-sref Angularjs but my query is not for scope value in as parameter in data-ui-sref.
ui-sref value is a scope expression. Therefore, you don't have to interpolate the scope value but pass it as if it was javascript with direct access to your scope like: <a data-ui-sref="app.admin({ startFrom: dateFrom, endTo: dateTo })">click</a>.

dynamically change ng-repeat filter using params from ui-sref

So I have a custom filter set up in my ng-repeat list which I can change dynamically using different buttons with the same page.
My question is, how do I go about changing this filter, with a value outside of the page.
To clarify, I have an ng-repeat list on my 'list.view.html' and I would like to be able to press a button on my homepage, which includes a filter value, and load the 'list.view.html' with the filtered results including the param of the button on my homepage.
To iterate further,
above my ng-repeat on list.view.html, I include buttons like so:
<button class="sortBy" ng-click="myFilter = { statusOpen : true }">Open</button>
Which updates my ng-repeat to only include items where the statusOpen boolean evaluates to true.
Here is the filter in my ng-repeat
<li class="list-group-item animate-repeat" data-ng-repeat="task in vm.tasks | filter:search | filter:myFilter>
How would I achieve the same result by clicking a button on the homepage which routes to the list.view.html page with filtered results?
I have tried setting a param filter in the controller for the list.view.html however I couldn't get it to work.
e.g <a ui-sref="tasks.list({ myFilter = { onlineTask : 'true' } })"> on my homepage and :: on my client.routes.js
params: {
myFilter: null
}
console error message
angular.js:11706 Error: [$parse:syntax] Syntax Error: Token '=' is unexpected, expecting [:] at column 12 of the expression [{ myFilter = { onlineTask : 'true' } }] starting at [= { onlineTask : 'true' } }].
http://errors.angularjs.org/1.3.20/$parse/syntax?p0=%3D&p1=is%20unexpected%2C%20expecting%20%5B%3A%5D&p2=12&p3=%7B%20myFilter%20%3D%20%7B"
I am just looking for some general direction on how to proceed with this please.
Thanks very much in advance
I think that setting needed params in angular-ui filter is the best way to achive what you want.
You just have to remember to:
Set up you URL properly (include param in URL) and process params using $stateParams service in yout controller. You may use array if you have more then one filter:
$stateProvider
.state('search', {
url: "/search/?myFilter",
templateUrl: 'search.html',
controller: function ($stateParams) {
// Get filter(s)
console.log($stateParams.myFilter);
}
})
Properly assign your params in ui-sref (use colon!):
<a ui-sref="filter({ myFilter: ['filter1','filter2'] })">Go and filter</a>
See example: http://plnkr.co/edit/QOHNYHVPRJ8iBm3Adjcj?p=preview

Angular Controller organization and ui-router

I am trying to make a simple list display, but I am having some concerns about Controllers organization.
In my application, I have 2 states, items and state2. In items, I want to display a list of Items, and "something else" in state2.
But I also have a + button at the top of my application that can add an item to my list. And I want that button to be displayed in both states. Here is an illustration:
Now, I would like to put my items related functions, in a specific controller ItemsCtrl. So this would be my routes:
myApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/items");
$stateProvider
.state('items', {
url: "/items",
templateUrl: "partials/items.html",
controller: "ItemsCtrl"
})
.state('state2', {
url: "/state2",
templateUrl: "partials/state2.html",
controller: "State2Ctrl"
});
});
And this would be my ItemsCtrl:
myApp.controller('ItemsCtrl',function($scope){
$scope.items = ["One",'Two'];
})
And now, I make a new MainCtrl to handle the + button that should be present on any page:
myApp.controller('MainCtrl',function($scope){
$scope.promptItem = function(){
var result = prompt('Add Item', 'New Item', ['ok'], 'Zero');
$scope.items.push(result.input1); //This line doesn't work
}
})
What is the best organization for this kind of interface? Do I really need to put my $scope.items in my MainCtrl?
I'd rather not, and the best thing I think would even be to put the promptItem function in ItemsCtrl, what do you think?
Thanks a lot for your answers, I am completely new to this world :)
EDIT: Here is my HTML structure, my + button is in the root file:
<button ng-click="promptProduct()">Add Item</button>
<a ui-sref="state1">State 1</a>
<a ui-sref="state2">State 2</a>
<div ui-view></div>
This is probably a great place to leverage an Angular service. The problem from what I understand is that you are struggling to share state between different parts of your application. I would recommend creating, e.g. a ListService, as such:
myApp.service('ListService', ListService);
function ListService () {
this.list = ['One', 'Two'];
}
ListService.prototype = {
addItemToList: function (newThing) {
var item = // some initialization of an item from the passed value
this.list.push(item);
}
};
You can then inject ListService anywhere you need access to the data itself. Both the list view and the state2 need it -- the former to actually render the list, and the latter to modify its contents. The method I described above lets you separate the data (the list itself) from the presentation / UI interaction.
[edit]
Likewise, if you want a button that lets you add a new item in both of your views, you could create a directive that receives ListService and prompts the user with a modal when clicked.

Updating an array in the controller scope from a partial

I am using an isteven-multi-select with a controller (ListController) that is using "$scope.mainCategories" for content that is populated by the "ticked" boolean value.
In the header of the application, I am using a select element to allow the user to select a single category (and then be forwarded to the list page). I am using this select element to toggle the ticked boolean value in $scope.mainCategories.
Both are using the same controller, although references separately through UI-Router (possible issue)
views: {
'header#index': {
templateUrl: 'header.html',
controller: "ListController"
},
'container#index': {
templateUrl: 'search.html',
controller: 'ListController'
},
}
then the isteven-multiselect and the select element are in the same partial - the functionality works - when on separate partials the functionality is broken.
Plunker
x might not be what you expect because you can't look for index of object in this line unless you're passing in the actual object:
var x = $scope.mainCategories.indexOf(item);
I assume you're trying to pass in something like:
{
category: "Adventure",
ticked: false
}
and to get the index, it won't work. You need to loop over the array and match the category, for example.
Your approach for modifying the outside array is fine, though.
See this example to see what I mean:
var people = [
{name: 'Shomz'},
{name: 'John'}
];
alert(people.indexOf({ name: 'John'})); // -1: the copy of object not found
alert(people.indexOf(people[1])); // 1: actual reference found
Scope update
To manually update the scope, either wrap the code in a $timeout callback, or use:
$scope.$apply();
$scope.update = function(item) {
item.ticked = true; // ?
};
$scope.mainCategories = [{
category: "Adventure",
ticked: false
},{category: "Fantasy",
ticked: false}];
Just have your function take the object you want to modify and pass that in from the view.

Resources