I have a set of tabs in Ionic framework which show a list of movies:
<script id="tabs.html" type="text/ng-template">
<ion-tabs tabs-style="tabs-icon-top" tabs-type="tabs-positive">
<ion-tab title="Movies" icon="ion-film-marker" href="#/tab/movies">
<ion-nav-view name="movies-tab"></ion-nav-view>
</ion-tab>
</ion-tabs>
</script>
<script id="movies.html" type="text/ng-template">
<ion-view title="'Movies'">
<ion-content has-header="true" padding="false">
<div class="list">
<a ng-repeat="item in movies" href="#/tab/movies/{{item.id}}" class="item item-thumbnail-left item-text-wrap">
<img ng-src="{{ item.image }}">
<h2>{{ item.title }}</h2>
<h4>{{ item.desc }}</h4>
</a>
</div>
</ion-content>
</ion-view>
</script>
Each of the items in the list is linked to #/tab/movies/{{item.id}}, for example, #/tab/movies/27. My movies are defined in the controler
.controller('MyCtrl', function($scope) {
$scope.movies = [
{ id: 1, title: '12 Rounds', desc: 'Detective Danny Fisher discovers his girlfriend has been kidnapped by a ex-con tied to Fisher\'s past, and he\'ll have to successfully complete 12 challenges in order to secure her safe release.', image: ''}
];
My pages are routed as below:
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('tabs', {
url: "/tab",
abstract: true,
templateUrl: "tabs.html"
})
.state('tabs.movies', {
url: "/movies",
views: {
'movies-tab': {
templateUrl: "movies.html",
controller: 'MyCtrl'
}
}
})
$urlRouterProvider.otherwise("/tab/movies");
})
What I need to do now is when each item on the above list is clicked, it takes it to it's own page, #/tab/movies/{{item.id}}, where I can display things like item.title or item.image, along with a back button to go to the list.
In order to do this, from what I can tell, I need to create a blank ng-template with a placeholder for the information, and then some how pass this information to it when clicked, but I'm not sure how to do this.
In your stateProvider config, you need to add a placeholderFor for the movie id, something like:
.state('tabs.movies', {
url: "/movies/:id",
views: {
'movies-tab': {
templateUrl: "movies.html",
controller: 'MyCtrl'
}
}
})
see https://github.com/angular-ui/ui-router/wiki/URL-Routing#stateparams-service
What are you looking for is probably service/factory where you can store list of movies and then retrieve full list for MyCtrl or just a single movie object for movie page.
angular.module('myAppName')
.factory('MovieService', function () {
return {
MoviesList: [
{movie object}
],
GetAllMovies: function () {
return this.MoviesList;
},
GetMovieById: function (id) {
//iterate MoviesList and return proper movie
}
}
}
that service can be then injected into your controllers
.controller('MyCtrl', function($scope, MoviesService) {
$scope.movies = MoviesService.GetAllMovies();
}
and same goes for a movie view controller:
.controller('ShowMyMovie', function($scope, MoviesService) {
$scope.movie = MoviesService.GetMovieById(//retrieve_id_from_routing_service);
}
then in template for this view you can simply use {{movie.title}} to display informations
Related
Would this result in presenting the page with header, footer and content block filled with content.list view?
$stateProvider
.state('contacts', {
abstract: true,
url: '/contacts',
views: {
header: { templateUrl: 'admin/header.html'},
content: {
templateUrl: 'contacts.html',
controller: function($scope){
$scope.contacts = [{ id:0, name: "Alice" }, { id:1, name: "Bob" }];
}
},
footer: { templateUrl: 'admin/footer.html'}
}
})
.state('contacts.list', {
url: '/list',
templateUrl: 'contacts.list.html'
})
.
<!-- index.html -->
...
<div ui-view="header"></div>
<div ui-view="content"></div>
<div ui-view="footer"></div>
...
.
<!-- contacts.html -->
<h1>Contacts Page</h1>
<div ui-view></div>
.
<!-- contacts.list.html -->
<ul>
<li ng-repeat="person in contacts">
<a ng-href="#/contacts/{{person.id}}">{{person.name}}</a>
</li>
</ul>
Yes, this will work. There is a working plunker.
The parent view's $scope (the view, defined in state 'contacts' views as a 'content') and its scope, will be a source for prototypical inheritance.
And that means, that its properties will be available in the child state 'contacts.list', because it is injected into that 'content' view
There is in detail more about it:
How do I share $scope data between states in angularjs ui-router?
To prove, it, we can extend the code snippet above with a list controller and inject some more contacts
...
.state('contacts.list', {
url: '/list',
templateUrl: 'contacts.list.html',
controller: 'listCtrl', // new controller
})
}
])
// we get already initiated contacts... coming from parent view
.controller('listCtrl', ['$scope', function($scope) {
$scope.contacts
.push({ id: 2, name: "from a child" });
}])
Check it here
Been following through some Angular JS tutorials and I'm trying to translate them into the Ionic framework but running into some problems. I'm trying to write a reusable HTML control but the model is not being bound to the view. Here is my code:
//App.js
angular.module('starter', ['ionic', 'starter.controllers', 'starter.directives'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'templates/menu.html'
})
.state('app.playlists', {
url: '/playlists',
views: {
'menuContent': {
templateUrl: 'templates/playlists.html',
controller: 'PlaylistsCtrl'
}
}
})
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/app/playlists');
});
//Controller.js
angular.module('starter.controllers', [])
.controller('PlaylistsCtrl', function($scope) {
$scope.playlists = [
{ title: 'Reggae', id: 1 },
{ title: 'Chill', id: 2 },
{ title: 'Dubstep', id: 3 },
{ title: 'Indie', id: 4 },
{ title: 'Rap', id: 5 },
{ title: 'Cowbell', id: 6 }
];
})
//Directives.js
angular.module('starter.directives', [])
.directive('testInfo', function(){
return {
restrict: 'E',
scope: {
info: '='
},
templateUrl: 'templates/test_view.html'
};
});
//Test View
<button class="item ion-item" >
The playlist title is + {{playlist.title}}
</button>
//App View
<ion-content>
<ion-list>
<ion-item ng-repeat="playlist in playlists" >
<div ng-click="playListSelected($index)">
<test-info info="playlist"></test-info>
</div>
</ion-item>
</ion-list>
</ion-content>
</ion-view>
//Index.html
I know I'm linking my js files correctly, however in the custom view the playlist.title never has a value. The controller never seems to bind to the html element. Double checking some angular tutorials I was going through, I'm following a similar approach and can't seem to figure out what the problem is.
In your directive you are defining a value on the directive's scope named info. So inside the template for the directive, you need to reference that with the name info, not playlist.
<button class="item ion-item" >
The playlist title is + {{info.title}}
</button>
I have an app with a tabbed interface, which consists of three tabs. When the user takes certain actions on tab1, it dynamically creates elements that should appear on the second tab. The problem is when I try to dynamically create that content within my javascript, I'm getting cannot set attribute of "null", which I'm assuming is because the second tab isn't loaded into the dom yet. If I first navigate to the second tab, then back to the first tab, it works fine. I'm not really using angular the way it's normally probably used. Everything is done in javascript. I just have a barebones app.js for the underlying UI.
Essentially, I just want to have all three tabs loaded into the DOM on app startup so I can dynamically modify the contents of any tab from any other tab. Not sure how to do this. Here's what my app.js looks like:
var myApp = angular.module('starter', ['ionic','ngCordova'])
myApp.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if(window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if(window.StatusBar) {
StatusBar.styleDefault();
}
$cordovaStatusbar.overlaysWebView(true)
$cordovaStatusbar.styleHex('#4a87ee')
$ionicConfigProvider.views.forwardCache(true);
});
});
myApp.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('tabs', {
url: "/tab",
abstract: true,
templateUrl: "templates/tabs.html"
})
.state('tabs.home', {
url: "/home",
views: {
'home-tab': {
templateUrl: "templates/home.html"
}
}
})
.state('tabs.favorites', {
url: "/favorites",
views: {
'favorites-tab': {
template: "templates/favorites.html",
controller: 'AppCtrl'
}
}
})
.state('tabs.settings', {
url: "/settings",
views: {
'settings-tab': {
templateUrl: "templates/settings.html"
}
}
});
$urlRouterProvider.otherwise("/tab/home");
})
myApp.controller('AppCtrl', function($scope) {
})
And my basic app structure/html looks like this:
<ion-nav-bar class="bar-positive"></ion-nav-bar>
<ion-nav-view></ion-nav-view>
<script id="templates/tabs.html" type="text/ng-template">
<ion-tabs class="tabs-positive tabs-icon-only">
<ion-tab title="Videos" icon-on="ion-ios-home" icon-off="ion-ios-home-outline" href="#/tab/home">
<ion-nav-view name="home-tab"></ion-nav-view>
</ion-tab>
<ion-tab title="Favorites" icon-on="ion-ios-star" icon-off="ion-ios-star-outline" href="#/tab/favorites">
<ion-nav-view name="favorites-tab"></ion-nav-view>
</ion-tab>
<ion-tab title="Settings" icon-on="ion-ios-gear" icon-off="ion-ios-gear-outline" href="#/tab/settings">
<ion-nav-view name="settings-tab"></ion-nav-view>
</ion-tab>
</ion-tabs>
</script>
<!-- **************************** HOME TAB **************************** -->
<script id="templates/home.html" type="text/ng-template">
<ion-view view-title="Lmao!Tube">
<ion-content has-bouncing="true" overflow-scroll="true" class="iframe-wrapper">
<div id="videoList"> </div>
</ion-content>
</ion-view>
</script>
<!-- **************************** FAVORITES TAB **************************** -->
<script id="templates/favorites.html" type="text/ng-template">
<ion-view view-title="Favorites" >
<ion-content has-bouncing="true" overflow-scroll="true" class="iframe-wrapper">
<div id="favoriteList"></div>
</ion-content>
</ion-view>
</script>
<!-- **************************** SETTINGS TAB **************************** -->
<script id="templates/settings.html" type="text/ng-template">
<ion-view view-title="Settings">
<ion-content>
</ion-content>
</ion-view>
</script>
Actually after rereading your question, you want to do it a different way. Once you click on the tab, it is placed on the stack and the content is rendered, that's why it only works when you push back and forward. What would be a better way is utilizing AngularJS and the application framework by saving changes like boolean values in a Service. A service is an object instantiated only once to hold information and pass it around from controller to controller. You can use the service to hold values that the controller dynamically creates content from, and in your templates you can use AngularJS's directives like ng-show and ng-if etc...
For instance in services.js you could have:
angular.module('starter.services', [])
.service('MyService', function() {
var Stuff = {};
this.set = function(key, value) {
Stuff[key] = value;
};
this.get = function(key) {
return Stuff[key];
}
});
And in your home controller
.controller('HomeCtrl', function(MyService, $scope) {
MyService.set('home', true);
})
And in your favorites controller
.controller('FavCtrl', function(MyService, $scope) {
if (MyService.get('home') === true) {
// set a variable or return list or query or whatever you want
// lets say it's an array
$scope.list = [1,2,3];
} else {
$scope.list = [4,5,6];
}
})
And in your template you could do something like:
<div ng-repeat="i in list">
{{i}}
</div>
And that should print out 1 2 3 if they clicked home tab, and 4 5 6 if not.
If you're new to angular go here: http://campus.codeschool.com/courses/shaping-up-with-angular-js/intro?utm_source=google&utm_medium=cpc&utm_campaign=course&gclid=CjwKEAjw9bKpBRD-geiF8OHz4EcSJACO4O7TsJ3Mx9m9DOH47-6rmFshzUkkkHzJFhJcNiPl1it9JRoCN_fw_wcB
Pretty nifty course that gets you knowing some things about AngularJS pretty fast to work with Ionic. Ionic is a great framework.
I would like to direct the pages of templateUrl , en route, to the wizard.html page. To filter fixed items to their respective pages , I use: | filterBy: ['href']:'/sound-waves' , for example. How could insert the items dynamically on one page ?
angular.module('tareasApp')
.controller('NatureCtrl', function ($scope, $routeParams, $sce, $location, $anchorScroll) {
$scope.items =[
{
href:'/sound-waves',
img:'waves.jpg',
video:'//www.youtube.com/watch?v=OG2eGVt6v2o',
description:'Those Relaxing Sounds of Waves'
},
{
href:'/nature-relaxing-sound',
img:'ocean.jpg',
video:'//www.youtube.com/watch?v=SWR0GdC7_40',
description:'Nature Sounds Relaxing Ocean Sounds'
}
];
});
Page wizard.html
<div ng-controller="NatureCtrl">
<div ng-repeat="item in items | filterBy: ['href']: ''" >
<img ng-src="images/{{ item.img }}" width="400" height="200" >
<p>{{item.description}}</p>
<iframe width="655" height="400" ng-src="{{ item.video }}" frameborder="0" allowfullscreen></iframe>
</div>
</div>
Route
angular.module('tareasApp')
.config(function ($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider
.when('/sound-waves', {
templateUrl: 'views/wizard.html',
controller: 'NatureCtrl'
})
.when('/nature-relaxing-sound', {
templateUrl: 'views/wizard.html',
controller: 'NatureCtrl'
})
.otherwise({
redirectTo: '/'
});
});
The goal is to avoid having multiple pages with the same structure.
Edited: The names of the pages are not in sequence so no . I had put to make it easier to understand . ( Had written as: page-one , page-two changed to sound-waves, nature-relaxing-sound )
Edited: Put the ...controller('NatureCtrl', function... involving the items array for better understanding.
You are right that creating a route for each URL is the wrong way to go, which is why $routeProvider supports route params.
You can define your route as follows:
$routeProvider
.when("/:pageName", {
templateUrl: "views/wizard.html",
controller: "NatureCtrl"
});
and pageName will be available as a $routeParam.pageName:
.controller("NatureCtrl", function($scope, $routeParams){
// ... pageName could be: "sound-waves" or "nature-relaxing-sound"
$scope.pageName = $routeParams.pageName;
});
If the items are coming from a service, say ItemsService, you could also use the resolve property to obtain the items and even pre-filter them as they are coming from the service, as an inject-able parameter for your controller. Here's how it could look like:
$routeProvider
.when("/:pageName", {
templateUrl: "views/wizard.html",
resolve: {
item: function(ItemService, $route){
// $routeParams here would not yet have the params for this route
return ItemsService.getItemsForPage($route.current.params.pageName);
}
},
controller: function($scope, item){
$scope.itemForThePage = item;
}
})
Currently, main list html works
<div class="post row" ng-repeat="(postId, post) in posts">
{{ post.title }}
But when I click the item (one of the many in the list) and go to another page, the new page does not display the item in detail?
When I add the line below, including $stateParams in the dependencies, into the controller js file, {{ post.title }} appears but the data does not pass through.
$scope.post = $scope.posts[$stateParams.id]
UPDATE
This is the states code. (ignore missing syntax...im shortening it). Someone helped resolved the previous issue and provided the below codes for the viewing part (the last 2 states).
.state('tab.view', {
url: '/posts/:postId',
views: {
'tab-view': {
templateUrl: 'templates/tab-showpost.html',
controller: 'PostViewCtrl'
How the details are access after clicking on the list item.
app.controller('PostViewCtrl', function ($scope, $stateParams, Post) {
$scope.Post = Post.find($stateParams.postId); //i think this may be broken
One key piece that is missing in your question is how your stateProvider is configured. Please ensure that your states have the url set up correctly to send data though state parameters. I have a codepen here that shows one way to to have a list of items where clicking on one will take the user to it's details. Note how the states are set up...
angular.module('ionicApp', ['ionic'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('tabs', {
url: "/tab",
abstract: true,
templateUrl: "tabs.html"
})
.state('tabs.home', {
url: "/home",
views: {
'home-tab': {
templateUrl: "home.html",
controller: 'HomeTabCtrl'
}
}
})
.state('tabs.detailview', {
url: "/detailview/:index", //NOTE: :index is how you use $stateParams later on.
views: {
'home-tab': {
templateUrl: "detailview.html",
controller: 'DetailviewTabCtrl'
}
}
});
$urlRouterProvider.otherwise("/tab/home");
});
Then, in your controller...
.controller('DetailviewTabCtrl', function($scope,$stateParams) {
$scope.id = parseInt($stateParams.index);//NOTE: This is the same 'index'
$scope.previous = parseInt($stateParams.index) - 1;
$scope.next = parseInt($stateParams.index) + 1;
});
I don't know what {{post.url}} is in the ng-repeat; but I think you need a different $state that should handle the detail View.
Do something like:
<div class="post row" ng-repeat="(postId, post) in posts">
<a ui-sref="postDetail({id:post.id })">{{ post.title }}</a>
</div>
You then need a state definition in your app config's $stateProvider like this:
.state('postDetail', {
url: "/post/:id",
//NOTE: :id will be accessed from the controller using $stateParams later on.
templateUrl: "post_detail.html",
controller: 'PostDetailCtrl'
}) ...
That should do it.