How to change the id of clicked image - css

I want to change the id of selected image on click. Currently, clicking one image will affect all the images with [id]="available". How can I change for specific image. Here is my html
<ion-row>
<ion-avatar *ngFor="let seat of row1.seats; let i=index;" id="item-
{{i}}">
<ion-label>{{seat.label}}</ion-label>
<img *ngIf="seat.booked===true" src="assets/st.png" id="booked">
<img *ngIf="seat.booked===false" src="assets/st.png"
[id]="available" (click)="selectedSeat(seat.id)">
</ion-avatar>
</ion-row>
Here is ts.
available = "available";
selectedSeat(id) {
this.available = "selected";
}
css:
#available {
background-color: cornsilk;
}
#selected {
background-color: #614056;
}

You can use setAttribute() of Renderer2 and template reference like following:
In template, add #myImg to img tag:
<img *ngIf="seat.booked===false" src="assets/st.png #myImg (click)="selectedSeat(myImg, seat.id)">
In component (.ts) file, inject Renderer2 and use it in selectedSeat method:
constructor(private renderer: Renderer2){}
selectedSeat(seletctedSeat: ElementRef, id) {
this.renderer.setAttribute(seletctedSeat.nativeElement, 'id', 'selected');
}
!BUT!
I think assigning id attribute is not the right way to do it. ID should be unique by nature, so you are assignin same ID to multiple elements. This sounds wrong. I think you should change CSS class if you only want to change styling but not applying any logic (like doing something with selected seat) with following:
In .ts file:
selectedSeat(seletctedSeat: ElementRef, id) {
this.renderer.addClass(seletctedSeat.nativeElement, 'selected');
}
In CSS:
.selected {
background-color: #614056;
}
UPDATE
You can create an array and push selected ID's to it. Then check if the array includes the seat.id:
In template:
<img *ngIf="seat.booked===false" src="assets/st.png"
[ngClass]="selectedSeatList.includes(seat.id) ? 'selected' : 'available'" (click)="toggleSelection(seat.id)">
In component (.ts) file:
selectedSeatList: Array<number> = [];
toggleSelection = (seatID) => {
if(this.selectedSeatList.includes(seatID)){
this.selectedSeatList = this.selectedSeatList.filter(id => id !== seatID);
}else{
this.selectedSeatList.push(seatID);
}
}

It looks like you want to change the background-color for an ngFor-created element with an index, when that index is selected through the selectedSeat() function.
If this is accurate, I would say to ignore the element's id entirely and use class instead.
You could start by using your selectedSeat() function to accept the template element's index as well as seat.id, then change your available variable to something like currentlySelectedSeat to the currently selected ngFor element's index:
currentlySelectedSeat = 0; // <-- default to first index (if you wish)
selectedSeat(seatId, index) {
if (index) { // <-- basic check
this.currentlySelectedSeat = index; // <-- assign id
}
// do whatever else with seatId
}
If you slightly alter your css to define classes instead of ids like this:
.available {
background-color: cornsilk;
}
.selected {
background-color: #614056;
}
..you could then use a ternary in an ngClass and structure your template like this:
<ion-row>
<ion-avatar *ngFor="let seat of row1.seats; index as i;"> // <-- id not necessarily needed. index still assigned to i, just written differently
<ion-label>{{seat.label}}</ion-label>
<img *ngIf="seat.booked===true" src="assets/st.png" class="booked"> // <-- unless there will only ever be one of these images, use class instead of id
<img *ngIf="seat.booked===false" src="assets/st.png"
[ngClass]="currentlySelectedSeat === i ? 'selected' : 'available'" // <-- *this line clarified below
(click)="selectedSeat(seat.id, i)"> // <-- expand function to accept template index as well.
</ion-avatar>
</ion-row>
*Clarified ngClass template line: this is the same as writing:
if (available === i) { // <-- if the variable named available's value is the same as the index which was passed through selectedSeat() on click
return 'selected'; // <-- give ngClass a string which corresponds to .selected
} else {
return 'available'; // <-- give ngClass a string which corresponds to .available

Related

How to call a function inside a child component in `Vue3` created through a `v-for` loop?

I am currently building a form builder with vue3 composition API. The user can add in different types of inputs like text, radio buttons etc into the form before saving the form. The saved form will then render with the appropriate HTML inputs. The user can edit the name of the question, eg Company Name <HTML textInput.
Currently, when the user adds an input type eg,text, the type is saved into an ordered array. I run a v-for through the ordered array and creating a custom component formComponent, passing in the type.
My formComponent renders out a basic text input for the user to edit the name of the question, and a place holder string for where the text input will be displayed. My issue is in trying to save the question text from the parent.
<div v-if="type=='text'">
<input type="text" placeholder="Key in title"/>
<span>Input field here</span>
</div>
I have an exportForm button in the parent file that when pressed should ideally return an ordered array of toString representations of all child components. I have tried playing with $emit but I have issue triggering the $emit on all child components from the parent; if I understand, $emit was designed for a parent component to listen to child events.
I have also tried using $refs in the forLoop. However, when I log the $refs they give me the div elements.
<div v-for="item in formItems" ref="formComponents">
<FormComponent :type="item" />
</div>
The ideal solution would be to define a method toString() inside each of the child components and have a forLoop running through the array of components to call toString() and append it to a string but I am unable to do that.
Any suggestions will be greatly appreciated!
At first:
You don't really need to access the child components, to get their values. You can bind them dynamically on your data. I would prefer this way, since it is more Vue conform way to work with reactive data.
But I have also implemented the other way you wanted to achieve, with accessing the child component's methods getValue().
I would not suggest to use toString() since it can be confused with internal JS toString() function.
In short:
the wrapping <div> is not necessary
the refs should be applied to the <FormComponents> (see Refs inside v-for)
this.$refs.formComponents returns the Array of your components
FormComponent is used here as <form-components> (see DOM Template Parsing Caveats)
The values are two-way bound with Component v-model
Here is the working playground with the both ways of achieving your goal.
Pay attention how the values are automatically changing in the FormItems data array.
const { createApp } = Vue;
const FormComponent = {
props: ['type', 'modelValue'],
emits: ['update:modelValue'],
template: '#form-component',
data() {
return { value: this.modelValue }
},
methods: {
getValue() {
return this.value;
}
}
}
const App = {
components: { FormComponent },
data() {
return {
formItems: [
{ type: 'text', value: null },
{ type: 'checkbox', value: false }
]
}
},
methods: {
getAllValues() {
let components = this.$refs.formComponents;
let values = [];
for(var i = 0; i < components.length; i++) {
values.push(components[i].getValue())
}
console.log(`values: ${values}`);
}
}
}
const app = createApp(App)
app.mount('#app')
#app { line-height: 2; }
[v-cloak] { display: none; }
label { font-weight: bold; }
th, td { padding: 0px 8px 0px 8px; }
<div id="app">
<label>FormItems:</label><br/>
<table border=1>
<thead><tr><th>#</th><th>Item Type:</th><th>Item Value</th></tr></thead>
<tbody><tr v-for="(item, index) in formItems" :key="index">
<td>{{index}}</td><td>{{item.type}}</td><td>{{item.value}}</td>
</tr></tbody>
</table>
<hr/>
<label>FormComponents:</label>
<form-component
v-for="(item, index) in formItems"
:type="item.type" v-model="item.value" :key="index" ref="formComponents">
</form-component>
<button type="button" #click="getAllValues">Get all values</button>
</div>
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
<script type="text/x-template" id="form-component">
<div>
<label>type:</label> {{type}},
<label>value:</label> <input :type='type' v-model="value" #input="$emit('update:modelValue', this.type=='checkbox' ? $event.target.checked : $event.target.value)" />
</div>
</script>

Angular 6: How to change page background-color dynamically

I work on an Angular 6 app (with Bootstrap 4) and need to change the page background color depending on which page the user enters. Default is white, but for login and registration screen the page color needs to be blue.
What I found so far:
in ngAfterViewInit() using
this.elementRef.nativeElement.ownerDocument: this approach makes the
app more vulnerable to XSS attacks and I want to avoid that.
Set View Encapsulation to None in app.component.ts: this way I can
set the body color in the app.component, that is 1 step forward.
So, now I have in my app.component.css:
body {
background-color: blue;
}
Question:
How can I change that color value (in app.component) using a variable?
With [ngStyle] I can not reach the body background-color.
Maybe using a css variable? but how can I change the value of that css variable dynamically?
I'm new to Sass, but might this offer a solution?
My question is different from the other question on this subject as I need to be able tochange the color value dynamically.
use render2 and set class to body using document object
app.component.ts
constructor(private renderer: Renderer2) {
this.renderer.addClass(document.body, 'body-class');
}
Note: if you are toggling classes, just remove previous class before assigning new class
The way I would do it is based on the routes. When defining the routes, you can add extra data, for example a class name.
When the route changes (i.e. via navigation), the data from the active route can be used to set the class on the body tag.
This is how you can achieve this
Update the styles.css to add different classes for body:
body {
...
}
body.red {
background-color: #ff8181;
}
body.blue {
background-color: #a0c3ee;
}
Update the routes to add extra data, specifying the body class name. Add an extra data property, like bodyClass:
const routes: Routes = [
{ path: '', component: DefaultComponent },
{ path: 'red', component: RedComponent, data: { bodyClass: 'red' } },
{ path: 'blue', component: BlueComponent, data: { bodyClass: 'blue' } }
];
Write the code to read the bodyClass and set the class to the body element when navigation occurs. This can be done in the app.component.ts:
#Component({
selector: 'app-root',
template: `
<div>
<router-outlet></router-outlet>
<app-menu></app-menu>
</div>
`
})
export class AppComponent implements OnInit {
constructor(
#Inject(DOCUMENT) private document,
private renderer: Renderer2,
private router: Router,
private activatedRoute: ActivatedRoute) {
}
ngOnInit() {
this.router.events
.pipe(filter((event) => event instanceof NavigationEnd))
.pipe(map(() => this.activatedRoute))
.pipe(map((route) => {
while (route.firstChild) {
route = route.firstChild;
}
return route;
}))
.pipe(filter((route) => route.outlet === 'primary'))
.pipe(mergeMap((route) => route.data))
.subscribe((event) => this.updateBodyClass(event.bodyClass));
}
private updateBodyClass(customBodyClass?: string) {
this.renderer.setAttribute(this.document?.body, 'class', '');
if (customBodyClass) {
this.renderer.addClass(this.document?.body, customBodyClass);
}
}
}
Here is a demo on StackBlitz: https://stackblitz.com/edit/angular-ivy-rs1tai
Why not just define a separate class based on different background-color? For instance:
.blue {
background: blue
}
.green {
background: green
}
.grey {
background: grey
}
And then set these classes on the body using ng-class or ngClass whatever convention you use based on the page. This should be fairly easy to implement.
My favourite approach for doing stuff like this is to add a class to html tag depending on the route. For example, we have some code in our basic layout component (you could put it in your root component) that does this inside ngOnInit:
let wrapper = ''
const path = this.activatedRoute.snapshot.routeConfig.path
wrapper += this.tidyPath(path)
if (wrapper !== '') wrapper += '-'
const childPath = this.activatedRoute.snapshot.firstChild.routeConfig.path
wrapper += this.tidyPath(childPath)
this.routeWrapperCssClass = wrapper
$('html').addClass(this.routeWrapperCssClass)
This will add a class to your html tag to make it look like this (although you may have to tweak this code to suit your app):
<html class="registration">
....
</html>
The class will be instantly updated whenever you change route.
Now you can do this in your main stylesheet:
body {
background-color: pink;
}
html.registration body {
background-color: yellow;
}
You could also do things like hide elements based on the class added to the html tag like so:
.navbar {
display: block;
}
html.registration .navbar {
display: none;
}
Because you know what route you are on at all times you have total control via CSS.
PS you may want to use render2 instead of jQuery to do the DOM manipulation - see this article ... https://alligator.io/angular/using-renderer2 ... never used it myself before but almost identical to jQuery syntax - thanks to Pratap A.K answer for this
Personally i replace :
<body>
<app-root></app-root>
</body>
to
<app-root></app-root>
and then i add all the time the body on components or if i have multi
router-outlets i add it on app.component.css

Responsive Props in Vue Component

I have a prop called src in a Vue Component that binds to a :style like this:
<template>
<section :class="color" class="hero" :style="{ backgroundImage: src && 'url(' + src + ')' }">
<slot></slot>
</section>
</template>
<script>
export default {
props: ['src', 'color']
}
</script>
What I would like to do is to create a list of responsive props that get used depending on the device or screen size of the site visitor.
For instance, I imagine a list of props like src-sm, src-md, src-lg, etc. The user would enter different image urls for different device sizes and the style attr would use the appropriate url depending on the screen/size.
Is this possible in VueJS. If so, any idea how?
Thanks.
Unfortuently what you are trying to do is not trivial. This is because inline style tags can not accept media queries.
The spec declares:
The value of the style attribute must match the syntax of the contents of a CSS declaration block
Solution 1:
This solution is the simplest, perhaps not entirely what you are looking for.
It works by including img elements, and showing an hiding them via CSS.
<template>
<div>
<img class="image--sm" :src="src.sm" />
<img class="image--md" :src="src.md" />
<img class="image--lg" :src="src.lg" />
</div>
</template>
<script>
export default {
props: {
src: Object
}
}
</script>
<style>
.image--md,
.image--lg {
display: none;
}
#media (min-width: 400px) {
.image--sm {
display: none;
}
.image--md {
display: block;
}
}
#media (min-width: 600px) {
.image--md {
display: none;
}
.image--lg {
display: block;
}
}
</style>
Example: https://jsfiddle.net/h3c5og08/1/
Solution 2:
Image tags may not be the desired effect you are trying to achieve. This solution creates a style tag in the head and injecting the css content to change the background images.
You can not have style tags in Vue template. It will throw an error like:
Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side-effects in your templates, such as , as they will not be parsed.
As the error describes vue is designed the map state the UI. Using style tags in the template is prohibited because you can cause leaks to the outer world.
Although you can not declaratively styles in a template, we can use a bit of JS in the mounted hook of the component to add targetted and dynamic styles.
First we will need to constrain dynamic styles to this element. We can use the internal id of the created component this._uid, attaching to scope the css. (Note this is internal API so can be subject to change)
<template>
<div class="image" :data-style-scope="_uid">
</div>
</template>
The next part is to generate the style in a computed property, to later inject into a style block. You can expand on this computed property, to conditionaly assign properties ect. Note: keep the properties to the dynamic values only.
css () {
const selector = `.image[data-style-scope="${this._uid}"]`
const img = val => `${selector} { background-image: url("${val}"); }`
const sm = img(this.sm)
const md = img(this.md)
const lg = img(this.lg)
return `
${sm}
#media (min-width: 200px) { ${md} }
#media (min-width: 300px) { ${lg} }
`
}
This generated string from the css computed property is what we will now use when creating the style tag at mount. At mount we create a style node and append to the head. Assigning the nodes to the vm for references.
Using the references in the vm we can watch changes to the computed updating the style node.
Remember to clean up before destorying the component, removing the style node.
{
data () {
return {
// Reference data properties
style: null,
styleRef: null
}
},
mounted () {
// Create style node
let style = document.createElement('style')
style.type = "text/css"
style.appendChild(document.createTextNode(''))
// Assign references on vm
this.styleRef = style
this.style = style.childNodes[0]
// Assign css the the style node
this.style.textContent = this.css
// Append to the head
document.head.appendChild(style)
},
beforeDestroy () {
// Remove the style node from the head
this.style.parentElement.removeChild(this.style)
},
computed: {
css () {
// ...
}
},
watch: {
css (value) {
// On css value change update style content
this.style.textContent = this.css
}
}
}
Working Example: https://jsfiddle.net/bLkc51Lz/4/
You could also try the module described here: https://alligator.io/vuejs/vue-responsive-components/ which is called vue-responsive-components
It lets the component change its CSS depending on its own width (not on the entire browser's width)

Updating element CSS on PageA from button on PageB

I am using tabs for an app. I want a user button which when clicked on tab-detail.html to update the CSS of an element on its parent tab page tab.html
.controller('TabCtrl', function($scope,Tabs) {
$scope.tabs = Tabs.all() ;
// this populates the "tab.html" template
// an element on this page is: <span id="tab_selected_1">
// when user selects a listed item on tab.html
// it calls tab-detail.html
})
.controller('TabDetailCtrl', function($scope,$stateparams,Tabs) {
$scope.tabs = Tabs.get($stateparams.tabID) ;
// on tab-detail.html is a button <button ng-click="tabSelect()">
$scope.tabSelect = function(thisID) {
// update css on TabCtrl elementID
document.getElementById('tab_selected_1').style.color = "green" ;
}
})
The only way to get to tab-detail.html is via tab.html, thus tab.html must be loaded. But no matter what method I try I can't seem to find a way to access the element that is on another controller's page.
I have tried:
var e = angluar.element('tab_selected_1');
or
var e = angluar.element(document.querySelector('tab_selected_1') ;
e.style.color = "green" ;
The approach you are doing will never do a JOB for you as the DOM you want isn't available. You could achieve this by creating a sharable service that will maintain all of this variable in it and it will be used on UI. For ensuring binding of them your service variable should be in object structure like styleData OR you could also achieve this by creating angular constant.
app.constant('constants', {
data: {
}
});
Then you could inject this constant inside you controller & modify it.
.controller('TabCtrl', function($scope, Tabs, constants) {
$scope.constants = constants; //make it available constants on html
$scope.tabs = Tabs.all() ;
// this populates the "tab.html" template
// an element on this page is: <span id="tab_selected_1">
// when user selects a listed item on tab.html
// it calls tab-detail.html
})
.controller('TabDetailCtrl', function($scope,$stateparams,Tabs, constants) {
$scope.tabs = Tabs.get($stateparams.tabID) ;
$scope.constants= constants; //make it available constants on html
// on tab-detail.html is a button <button ng-click="tabSelect()">
$scope.tabSelect = function(thisID) {
// update css on TabCtrl elementID
$scope.constants.data.color = "green" ;
}
})
Markup
<div id="tab_selected_1" ng-style="{color: constants.data.color || 'black'}">
one way to do this is ....
1) Create a service
2) set a value to a variable in service on button click(tab-detail.html)
3) use that service variable value in tab.html
(Correction update at bottom)
#pankajparkar solution does work, however it does not work with IONIC as the IONIC Framework somehow overrides the DOM settings. Via the DOM Element inspector an see: style='color:green' being added inline to the ITEM/SPAN and can see the element defined as: element.style{ color: green}...but the color of the rendered HTML does not change....it stays black.
Further research shows this is somehow an IONIC problem as other users have the same problem. Other SOFs and blogs indicate that there appears to be a work around but I have yet to see it work.
The above is reformatted for others future use (even though it doesn't work with IONIC), thus I am still looking for a solution to work with IONIC:
.constant('constants', {
tabColors: {
curID:0,
},
})
.controller('TabCtrl', function($scope,Tabs,constants) {
$scope.constants = constants;
}
.controller('TabDetailCtrl', function($scope,$stateparams,Tabs,constants) {
$scope.constants = constants;
$scope.setItem= function(thisID) {
$scope.constants.tabColors.oldID = $scope.constants.tabColors.curID ;
delete $scope.constants.tabColors['tabID_'+$scope.constants.tabColors.curID] ;
$scope.constants.tabColors.curID = thisID ;
$scope.constants.tabColors['tabID_'+thisID] = 'green' ;
}
// HTML in Tab.html
<span id='tab_tabID_{{tab.tabID}}' ng-style="{color: constants.tabColors['tabID_'+tab.tabID] || 'black'}">
Some Text Here
</span>
//HTML in TabDetail.html
<button id="tab_button" class="button button-small button-outline button-positive" ng-click="setItem({{tab.tabID}});">
Select This Item
</button>
Correction: This method does work and does work with IONIC. The problem with IONIC is every element embedded within an ionic tag <ion-item>... <ion-nav>
...etc inherits its own properties from predefined classes...so you must either update the class (not optimal) or have ID tags on every element and/or apply CSS changes (using above method) to every child element. This is not optimal however it will work.
In my case my HTML actually looked like:
<span id='tab_tabID_{{tab.tabID}}' ng-style="{color: constants.tabColors['tabID_'+tab.tabID] || 'black'}">
<h2>Header Text Here</h>
<p>More text here</p>
</span>
The above CSS method works with this:
<span id='tab_tabID_{{tab.tabID}}'>
<h2 ng-style="{color: constants.tabColors['tabID_'+tab.tabID] || 'black'}">
Header Text Here
</h>
<p ng-style="{color: constants.tabColors['tabID_'+tab.tabID] || 'black'}">
More text here
</p>
</span>

Change ion-view header color in ionic

I am using the ionic starter menubar template. I would like to change the header background color of each page. I currently have:
<ion-view view-title="Search">
<ion-content>
<h1>Search</h1>
</ion-content>
</ion-view>
I tried:
<ion-view view-title="Search" class="bar bar-header bar-assertive">
<ion-content>
<h1>Search</h1>
</ion-content>
</ion-view>
But it does not work at all (content is not rendered). The header documentation does not help me. What is the correct way to do this?
Some ways to do this:
You could add the ion-nav-bar to each view.
<ion-view view-title="Page 1">
<ion-nav-bar class="bar-balanced">
<ion-nav-back-button></ion-nav-back-button>
</ion-nav-bar>
<ion-content>
...
</ion-content>
</ion-view>
Codepen example
You could also update the background-color (and any other properties) by using ng-style
Main navbar:
<ion-nav-bar class="bar-positive" ng-style="{'background-color': viewColor}">
<ion-nav-back-button></ion-nav-back-button>
</ion-nav-bar>
CSS:
.nav-bar-block, .bar {
background-color: inherit !important;
}
Controller:
$scope.$on('$ionicView.beforeEnter', function() {
$rootScope.viewColor = 'green';
});
Codepen example
Could not find a clean solution for this, but one hack might be to use the $stateChangeStart event and set the class name manually.
angular.module('starter')
.run(function ($rootScope) {
var element;
$rootScope.$on('$stateChangeStart', function (event, next) {
if (next.name) {
element = angular.element(document.querySelectorAll('ion-header-bar'));
switch(next.name) {
case 'tab.chats':
element.removeClass('bar-positive');
element.removeClass('bar-balanced');
element.addClass('bar-calm');
break;
case 'tab.dash':
element.removeClass('bar-calm');
element.removeClass('bar-balanced');
element.addClass('bar-positive');
break;
default :
element.removeClass('bar-calm');
element.removeClass('bar-positive');
element.addClass('bar-balanced');
}
}
});
});
fiddle
EDIT
The idea is same for sidebar template,
Updated fiddle
Notice the line
<ion-nav-bar class="bar-positive">
in menu.html template, it denotes the base header color class.
but subsequent changes to pages i.e states header color needs to be changed manually in $stateChangeStart event,
code:
.run(function ($rootScope) {
var element;
$rootScope.$on('$stateChangeStart', function (event, next) {
if (next.name) {
element = angular.element(document.querySelectorAll('ion-side-menu-content ion-header-bar'));
console.log(element);
switch(next.name) {
case 'app.search':
element.removeClass('bar-positive');
element.removeClass('bar-energized');
element.removeClass('bar-dark');
element.addClass('bar-assertive');
break;
case 'app.browse':
element.removeClass('bar-calm');
element.removeClass('bar-assertive');
element.removeClass('bar-dark');
element.addClass('bar-energized');
break;
default :
element.removeClass('bar-positive');
element.removeClass('bar-energized');
element.removeClass('bar-assertive');
element.addClass('bar-dark');
}
}
});
});
here the state name is checked to see which page is activating ex. app.search
then according to requirement specific color class is assigned removing other color classes.
ionic color options
hope this helps.
if you are using different states and each state has a different controller than just have a $scope variable like $scope.stateone = "true" etc. Then on your ion-nav-bar use ng-class="{'bar-positive': stateone, 'bar-stable': statetwo, 'bar-assertive': statethree}". ng-class takes classes and an expression, whichever expression is true that is the class that is assigned. you can use ng-class with any boolean expression. this is how you can have a different color on each page.
I modified the solution of #shakib to fit my needs, in my case the user sets the theme by clicking the app logo and thus the bar color should change. If this is your case you don't need to do the switch case because you want to change all views
$rootScope.$on("$stateChangeStart", function (event, toState) {
var element;
if (toState.name){
element = angular.element(document.querySelectorAll('ion-side-menu-content ion-header-bar'));
if (debugMode) console.log(element);
// I get the bar-class from my localStorage where I keep the user settings
var saved_bar_class = $localStorage.get('bar-class','bar-calm');
element.removeClass('bar-pink');
element.removeClass('bar-calm');
element.addClass(saved_bar_class);
// Here We could use a Switch Case on toState.name to put a different color to each state
}
});
Also when the user clicks the app logo I want to immediately change the bar color in order to give feedback to the user of what that button do. The above code won't do that because we haven't changed state yet, to fix this just add this code to your 'change theme' function
$scope.changeAppTheme = function () {
var element;
element = angular.element(document.querySelectorAll('ion-side-menu-content ion-header-bar'));
// some code to select the theme
element.removeClass('bar-pink');
element.removeClass('bar-calm');
element.addClass('bar-pink');
// some other code
};
In this case I just have two colors, the ionic calm and a pink one that I defined
Hope this helps someone
We got it working in CSS with:
.title.title-center.header-item {
background-color: black;
margin: 0px;
}
This means that we just refer to the Angular generated header classes directly with this CSS. Hope this helps!
Try using the following code:
<ion-view>
<ion-header-bar class="bar-assertive">
<h1 class="title">Search</h1>
</ion-header-bar>
<ion-content>
<h1>Search</h1>
</ion-content>
</ion-view>
You can override $bar-stable-text color (taken from _variables.scss from ionic lib)
For example, in your scss change
$bar-stable-text: green !default;
If you want to change the ion-nav-bar this here works like a charm:
1 . Create a main controller to take care of your index page and all views within it.
2. Add this function to the controller:
$scope.setNavColor = function(color){
for(var i =0; i < document.getElementsByTagName("ion-header-bar").length; i++){
classNames = document.getElementsByTagName("ion-header-bar")[i].className;
classNames = classNames.replace(/(bar-light|bar-stable|bar-positive|bar-calm|bar-balanced|bar-energized|bar-assertive|bar-royal|bar-dark)/g, color );
document.getElementsByTagName("ion-header-bar")[i].className = classNames;
}
}
3 . add on-select to your ion-tab tab so it will call the function whenever your tab is chosen:
<ion-tab href="#addr" on-select="setNavColor('PUT_YOUR_COLOR_HERE')> </ion-tab>
4 . add on-deselect to you ion-tab too if you want the color to go back to some value when you leave.
5 . Have fun!
//add these lines in your style.css file under /www/css/ yoyr project directory
.title.title-center.header-item {
background-color:#30393A;//#F38023!important; // for bg color
margin:0px!important;
margin-left:0px!important;
color: #ffffff!important;
text-align: center !important;
width: 100%;
}
put these lines in your style.css under /www/css/ directory of your ionic project
.title.title-center.header-item {
background-color:#4a87ee;//#F38023!important; // for bg color
margin:0px!important;
margin-left:0px!important;
color: #ffffff!important;
text-align: center !important;
width: 100%;
}
If you're using scss within your app, you can create your own custom bar class and use ionic's bar mixins in it.
$bar-custom-bg: #ccc;
$bar-custom-border: #eee;
$bar-custom-text: #fff;
$bar-custom-active-border: darken($bar-custom-border, 10%);
$bar-custom-active-bg: darken($bar-custom-bg, 10%);
.bar {
&.bar-custom {
#include bar-style($bar-custom-bg, $bar-custom-border, $bar-custom-text);
&.bar-footer{
background-image: linear-gradient(180deg, $bar-custom-border, $bar-custom-border 50%, transparent 50%);
}
.button {
#include button-style($bar-custom-bg, $bar-custom-border, $bar-custom-active-bg, $bar-custom-active-border, $bar-custom-text);
#include button-clear(#fff, $bar-title-font-size);
}
}
}
After defining your class, you can use your new custom bar class with ion-nav-bar directive.
<ion-nav-bar class="bar-custom">
<ion-nav-back-button></ion-nav-back-button>
</ion-nav-bar>

Resources