Angular material sidenav seems to have a left/right options:
<md-sidenav class="md-sidenav-**right**">
<md-sidenav class="md-sidenav-**left**">
Although it is called a "side"-nav, is it possible to use it as a "bottom"-nav?
if so how can it be done?
there is no bottom-nav as you said, but you can do it using https://material.angularjs.org/latest/demo/bottomSheet
VIEW
<div class="bottom-sheet-demo inset" layout="row" layout-sm="column" layout-align="center" >
<md-button flex="50" class="md-primary md-raised" ng-click="showBottomSheet()">Show</md-button>
</div>
JS
$scope.showBottomSheet = function() {
$scope.alert = '';
$mdBottomSheet.show({
templateUrl: 'bottom-sheet-template.html',
controller: 'BottomSheetCtrl'
}).then(function(clickedItem) {
$scope.alert = clickedItem['name'] + ' clicked!';
});
};
angular material does not support bottom nav .. you have to achieve it manually.
I think that what you are trying to achieve can be done by overwriting angular material styles to suit your needs. Just add some custom class or id to <md-sidenav> element and apply your styles.
Related
I have this little component:
.component('obsbox', {
restrict: 'E',
templateUrl: 'app/components/interactions/html/interactions.obsBox.partial.html',
controller: 'InteractionsController',
controllerAs: 'vm',
bindings: {}
});
All it does it produce a box with some text in it. Nothing spectacular. What I'd like to do is pass a few attributes into the tag and then display those attributes when it resolves.
<obsbox title1="Positive" title2="Experience" score="1"></obsbox>
That should give me a box with "1" in at the top and "Positive Experience" in the bottom. I haven't been able to find anything on SO or anywhere else that explains how I would do that in a way I can understand.
There's nothing in my controller or anywhere else that would be helpful to show you. My controllers are literally doing nothing at the moment.
Any advice?
Edit:
here's the html for the component:
<div layout="row" layout-align="start center" flex="11">
<div layout="column" layout-align="center center" flex="100">
<div layout="row" layout-align="center center" flex="100">
1
</div>
<div layout="row" layout-align="center center" flex="100">
<div layout="column" layout-align="center center" flex="100" style="font-size: x-small">
<div layout="row" layout-align="center center" flex="100">
POSITIVE
</div>
<div layout="row" layout-align="center center" flex="100">
ATTITUDE
</div>
</div>
</div>
</div>
</div>
In my ideal world "1", "Positive", and "Attitude" would come from from attributes on the obsbox tag.
Have you seen the example at https://docs.angularjs.org/guide/component ?
You should fill your bindings like this:
bindings: {
title1:"#",
title2="#",
score="#"
}
# denotes text binding. See the link above for more binding options.
You can then use {{ $ctrl.title1 }} and the other bindings in the template.
For an example, see https://plnkr.co/edit/Gv3TofiO0QyjAOkODjPv?p=info
You can load it into scope using a link function in your directive:
.component('obsbox', {
// the other directive parameters
link: (scope, element, attributes, controller) => {
controller.title1 = attributes.title1;
controller.title2 = attributes.title2;
}
});
The link function is executed once, upon directive compilation.
If you need to update the value, you need to add a watch to that attribute. Angular provides a way to observe attributes with the $observe function:
// in the link function body
attributes.$observe('title1', newValue => {
controller.title1 = newValue;
});
Note that this way, it's using plain strings, not Angular expressions. This means that if you want to have an expression, you would need the $parse service in the directive, or use interpolation at usage site.
Is it possible to switch between the attributes show and hide by button click (programmatically)? I have for example a card with a map and a list view.
These are usually displayed side by side. On mobile devices, but is for the List view flex = 100 increases. The map is no longer displayed. The user should however have the possibility to switch between the two views. How I can do that?
My example tags:
<md-card flex-gt-xs="40" flex-xs="100">
<list></list>
</md-card>
<md-button>toggle Views</md-button>
<md-card flex="60" hide-xs show-gt-xs >
<leaflet height="40vh" ></leaflet>
</md-card>
Update:
Summary
I would like to have 2 columns that can be switched on mobile devices, and side by side on larger devices.
I'm not 100% sure what you are asking but this CodePen demonstrates the basics of toggling programatically.
md-button has an ng-click attribute that calls the function toggle() which toggles the view value. view is passed to the ng-if of each card.
Markup
<div ng-controller="AppCtrl" ng-cloak="" ng-app="MyApp" style="height:100%" layout="column">
<md-card flex-gt-xs="40" flex-xs="100" ng-if="view">
Card 1
<list></list>
</md-card>
<md-button ng-click="toggle()">toggle Views</md-button>
<md-card flex="60" hide-xs show-gt-xs ng-if="!view">
Card2
<leaflet height="40vh" ></leaflet>
</md-card>
</div>
JS
angular.module('MyApp',['ngMaterial', 'ngMessages', 'material.svgAssetsCache', 'ngDialog'])
.controller('AppCtrl', function($scope) {
$scope.view = true;
$scope.toggle = function () {
$scope.view = !$scope.view;
}
});
You can replace ng-if with ng-show if you need to retain information in elements that you are toggling as ng-if recreates the element each time it is true.
I have found the solution. $mdMedia does all the magic.
js:
$scope.$watch(function () {
return $mdMedia('sm');
}, function (big) {
$scope.screenIsSmall = $mdMedia('sm');
});
View:
<md-card flex="60" ng-hide="screenIsSmall&&!showMap" style="max-height: 40vh">
<md-button ng-show="screenIsSmall" ng-click="showMap = !showMap">toggle</md-button>
<leaflet height="40vh"></leaflet>
</md-card>
app.component.html
<div fxLayout="column" fxLayout.gt-sm="row wrap">
<div fxFlex="50" class="flex-p">
<mat-slide-toggle
[checked]="isSlideChecked"
(change)="toggleChanges($event)"
>Hide/Show - card</mat-slide-toggle
>
</div>
</div>
<mat-card *ngIf="isSlideChecked">Simple card</mat-card>
app.component.ts
isSlideChecked: boolean = false;
toggleChanges($event: MatSlideToggleChange) {
this.isSlideChecked = $event.checked;
}
I'm creating my first Angular app and ran into a couple things that I just can't figure out. Whenever I include this:
<button ng-hide="results.length === projects.length" ng-click="limit = limit +3; gotoBottom()">Show More</button>
Inside of my template the app refuses to load but if I paste it anywhere outside of the template it works fine. I'd like to keep the button inside the template if at all possible so what on earth am I doing wrong?
Also, I'd like that button to also scroll to the #footer div and the ng-click doesn't seem to run this bit code:
$scope.gotoBottom = function() {
$location.hash('footer');
$anchorScroll();
};
I've created a Plunker of my code that can be found here:
https://plnkr.co/edit/MP4Pp4WLcn5EFb3pTEXx
By "template" if you are talking about projects template. Here is what you need to do.
Explanation:
The projects template need to have only one root element, so I added a div to wrap your project listing and show more button.
<div>
<div class="cards" ng-init="limit = 3">
<div class="card" ng-repeat="project in projects | limitTo: limit as results">
<div class="card-image">
<img src="{{project.img}}" alt="{{project.name}}" />
</div>
<div class="card-copy">
<h2>{{project.name}}</h2>
<p>{{project.desc}}</p>
<p><i class="fa fa-location-arrow"></i></p>
</div>
</div>
</div>
<button ng-hide="results.length === projects.length" ng-click="limit = limit +3; gotoBottom()">Show More</button>
<div id="footer" name="footer"></div>
</div>
For auto scroll: inject $timeout service
Explanation:
You did not had any div named footer so I added one just below the show more button and added a 100ms timeout, so that after your 3 projects load, it will scroll to the footer div. $timeout is very necessary because need to first render your projects and then scroll.
$scope.gotoBottom = function() {
$timeout(function() {
$location.hash('footer');
$anchorScroll();
}, 100);
};
Working Plunker: https://plnkr.co/edit/U3DDH57nh0Mqlpp2Txi4?p=preview
Hope this helps!
change the below code in projects.js
angular.module('portfolioApp')
.directive('projects', function() {
return {
templateUrl: 'projects.html',
controller: 'mainCtrl',
replace: true // remove directive tags
};
});
to
replace: false
it should do the trick. Plunker Link here
From couple of days I'm working on angularjs app. After 2 days of brain storming now I got to know how to use angularjs's new router+components+ng-outlet stuff.
Now, after moment of happiness one more strange problem came up. That is - In my app mainly 2 kind of pages are there.
Landing page (where I need only 1 ng-outlet)
Other pages (where I need 3 ng-outlet. It's like top navigation bar, side bar & main content area. See below screenshot )
So what i want, when user will move from landing page to some other page how i create dynamically 3 ng-outlet in my index.html file. So that, I can populate my top navigation bar component, side bar component & main content area.
Any clue, how to do handle such kind of situations ?
Thanks & Regards
index.html code
<body layout="column" ng-controller="AppCtrl">
<div ng-outlet="navigation" id="navigation">
</div>
<div layout="row" flex>
<md-sidenav layout="column" class="md-sidenav-left md-whiteframe-z2" md-component-id="left" md-is-locked-open="$mdMedia('gt-sm')">
<div ng-outlet="sidebar">
</div>
</md-sidenav>
<div layout="column" flex id="content">
<md-content layout="column" flex class="md-padding">
<div ng-outlet="main">
</div>
</md-content>
</div>
</div>
<script src="bower_components/angular/angular.min.js"></script>
<script src="bower_components/angular-animate/angular-animate.min.js"></script>
<script src="bower_components/angular-aria/angular-aria.min.js"></script>
<script src="bower_components/angular-material/angular-material.min.js"></script>
<script type="text/javascript" src="assets/js/router.es5.js"></script>
<script type="text/javascript" src="assets/js/app.js"></script>
</body>
I was facing the same issue, my workaround was to create a void component, with an empty controller and this template: "<div style='display:hidden;'></div>"
So, whenever i want to make a component "disappear" I assign it the void component, like this:
function appController($router) {
$router.config([
{ path: '/', redirectTo: '/splash' },
{ path: '/splash', components: { left: 'void', main: 'splash' } },
{ path: '/left', components: { main: 'splash', left: 'left' } }
]);
}
Hope it helps,
Renato
I am trying to set up custom themeing on my app, so what I am doing is letting the user choose certain themes and it will change the apps theme holistically. I have a service which sends a piece of json and listens for it changing inside the controller of each view. Now this works fine within the view itself - for reference here's some snippets of the working code.
my factory controlling the theme -
angular.module('demoApp')
.factory('templatingFactory', function () {
var meaningOfLife =
{
'h1': '#ea6060',
'bg': '#ffffff'
};
return {
setTheme: function(theme) {
meaningOfLife = theme;
},
getTheme: function() {
return meaningOfLife;
}
};
});
One of my example controllers showing and changing the theme (and listening for changes)
$scope.themeStore = templatingFactory.getTheme();
console.log($scope.themeStore);
//send new themes
$scope.themeOne = function () {
var newT1 = { 'h1': '#8A6516',
'bg': '#000000'};
templatingFactory.setTheme(newT1);
};
$scope.themeTwo = function () {
var newT2 = { 'h1': '#ffffff',
'bg': '#ea6060'};
templatingFactory.setTheme(newT2);
};
$scope.themeThree = function () {
var newT3 = { 'h1': '#ea6060',
'bg': '#ffffff'};
templatingFactory.setTheme(newT3);
};
//listen for new themes
$scope.watchThemes = templatingFactory.getTheme();
$scope.$watch(templatingFactory.getTheme, function (newTheme) {
$scope.themeStore = newTheme;
});
and then on the template/view itself i do something like this -
<h3 ng-style="{ 'color' : themeStore.h1 }">Title</h3>
So my issue is that this works fine inside the view. However the ng-view tag is inside the body and outside of it are the body containers, as well as the header and footer menus that I would like to be able to hook onto with this theme object. So my quesiton is, is there any way to use that scope outside of the ng-view? I don't think it's possible but I'm not sure how else I could access and put a ng-style on the header footer and body to change some css on it with this method I am using.
So for a simple reference it looks like this -
<body ng-app="myApp">
<div class="container">
<div class="header" ng-style="{ 'background-color' : themeStore.bg }">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<i class="fa fa-bars"></i>
</button>
<div class="headerLogo"></div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
</ul>
</div>
</div>
<div ng-view class="velocity-opposites-transition-slideUpIn" data-velocity-opts="{ duration: 500 }" ng-style="{ 'background-color' : themeStore.bg }"> </div>
<div class="footer">
<p></p>
</div>
</div>
</body>
So as you can see - I'm trying to hook onto the header to change the background color, which does not work like this. What I noticed though, is if I put it on the ng-view div itself, it works alright.
I would much appreciate any input as I've been stuck on this for a while. Thank you for taking the time to read!
The DOM elements outside of your ng-view must have controllers of their own, with templatingFactory injected as a dependency.
First I would modify the html like so:
<div class="header" ng-controller="headerController" ng-style="{ 'background-color' : themeStore.bg }">
Then add headerController to your module:
angular.module('demoApp').controller('headerController', function($scope, templatingFactory){
$scope.themeStore = templatingFactory.getTheme();
$scope.$watch(templatingFactory.getTheme, function (newTheme) {
$scope.themeStore = newTheme;
});
});
A more reusable solution would be to create a directive that adds this controller functionality to whatever DOM element it is applied to, but the above is a little more straight forward.
I think the best way to have angular functions and variables outside ui-view or ng-view is to use a global service. in this case you should do your theming logic inside 'templatingFactory'. Then inject this service not in your controllers, but in your module.
angular.module('demoApp').run(['$rootScope', 'templatingFactory', function($rootScope, templatingFactory){
$rootScope.templatingService = templatingFactory;
}]);
So your service will be avaible in the $rootScope. now you can use it this way.
<body ng-app="myApp">
<div class="container">
<div class="header" ng-style="{ 'background-color' : templatingService.getTheme().bg }"> </div>
</div>
</div>
ps: I'm relative new in angular too, so I don't know nothing about good/wrong practices!
For the directive approach, a simple example might look something like this:
demoApp.directive('themeHeader', function (templatingFactory) {
return {
restrict: 'A',
link : function (scope, element, attrs) {
scope.$watch(templatingFactory.getTheme, function () {
element.css('background-color', newTheme.bg);
});
}
}
});
and the html would look like this:
<div theme-header>
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"><i class="fa fa-bars"></i></button>
<div class="headerLogo"></div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right"></ul>
</div>