AngularJS md-tab & ng-repeat: adding custom style to specific tabs - css

I'm trying to customize a couple tabs because they're different.
Here's what I have:
<md-tabs>
<md-tab ng-repeat="tab in tabs" ng-class="tab.customClass">
<md-tab-label ng-bind="tab.label"></md-tab-label>
</md-tab>
</md-tabs>
My issue: the custom class is not in the compiled md-tab-item
NOTE: the gets replaced because it's only needed to generate tab buttons and panes.
I don't know how many tabs I have, so I cannot write CSS based on position.
Any ideas?

If you are trying to customize how the tab itself looks at the top you can do this through the use of a decorator. This will allow you to alter how directives behave at run time.
For example if you are trying to style the tab itself, that directive would be "md-tab-item"
(function () {
'use strict';
MdTabItemDecorator.$inject = ['$provide'];
angular.module('common').config(MdTabItemDecorator);
function MdTabItemDecorator($provide) {
$provide.decorator('mdTabItemDirective', [
'$delegate',
'$controller',
function ($delegate) {
var directive = $delegate[0];
directive.compile = function () {
return function (scope, elem, attrs) {
directive.link.apply(this, arguments);
elem.attr('style', 'color:red');
scope.tabIndex = scope.$parent.$index;
};
};
return $delegate;
}
])
}
})();
The above example would change the color of the tab text to red.
What's happening here is that we are creating a decorator mdTabItem with
function MdTabItemDecorator($provide) {
$provide.decorator('mdTabItemDirective', [
function ($delegate) {
...
}
])
This gives you access to the $delegate object which is a representation of the directive object that is about to be instantiated.
This allows us to make some modifications and return the delegate object changing how the directive behaves.
In this case I am taking the existing link function and extending it's functionality to set the style of the directive element.
directive.compile = function () {
return function (scope, elem, attrs) {
directive.link.apply(this, arguments);
elem.attr('style', 'color:red');
scope.tabIndex = scope.$parent.$index;
};
};

Related

Change css variables dynamically in angular

In my angular project, I have some css variables defined in top level styles.scss file like this. I use these variable at many places to keep the whole theme consistent.
:root {
--theme-color-1: #f7f7f7;
--theme-color-2: #ec4d3b;
--theme-color-3: #ffc107;
--theme-color-4: #686250;
--font-weight: 300
}
How can I update values of these variables dynamically from app.component.ts ? And What is the clean way to do this in angular ?
You can update them using
document.documentElement.style.setProperty('--theme-color-1', '#fff');
If u want to update many values, then create a object
this.styles = [
{ name: 'primary-dark-5', value: "#111" },
{ name: 'primary-dark-7_5', value: "#fff" },
];
this.styles.forEach(data => {
document.documentElement.style.setProperty(`--${data.name}`, data.value);
});
The main thing here is document.documentElement.style.setProperty. This line allows you to access the root element (HTML tag) and assigns/overrides the style values.
Note that the names of the variables should match at both places(css and js files)
if you don't want to use document API, then you can use inline styles on HTML tag directly
const styleObject = {};
this.styles.forEach(data => {
styleObject[`--${data.name}`] = data.value;
});
Then In your template file using ngStyle (https://angular.io/api/common/NgStyle)
Set a collection of style values using an expression that returns
key-value pairs.
<some-element [ngStyle]="objExp">...</some-element>
<html [ngStyle]="styleObject" >...</html> //not sure about quotes syntax
Above methods do the same thing, "Update root element values" but in a different way.
When you used :root, the styles automatically got attached to HTML tag
Starting with Angular v9 you can use the style binding to change a value of a custom property
<app-component-name [style.--theme-color-1="'#CCC'"></app-component-name>
Some examples add variables directly to html tag and it seem in the element source as a long list. I hope this helps to you,
class AppComponent {
private variables=['--my-var: 123;', '--my-second-var: 345;'];
private addAsLink(): void {
const cssVariables = `:root{ ${this.variables.join('')}};
const blob = new Blob([cssVariables]);
const url = URL.createObjectURL(blob);
const cssElement = document.createElement('link');
cssElement.setAttribute('rel', 'stylesheet');
cssElement.setAttribute('type', 'text/css');
cssElement.setAttribute('href', url);
document.head.appendChild(cssElement);
}
}

In VueJS, is there a way to make your binded styling react to the size change of the screen?

I have a div that is conditionally binded to a class in vueJS. The formula for my computed variable uses Screen.width. It seems to work correctly when first loading, but if I change the size of the screen it doesn't rebind with the new screen size, unless I refresh the page. Is there a way I can get my conditionally binding to honor the change in screen?
<div class="div_1" v-bind:class="{ horizontalScroll : showScroll }"/>
showScroll(){
return this.events.length*225>(screen.width*.84);
}
If you wanna do it this way, you will probably have to register a 'resize' listener. Your code should look something like this:
data: () => ({
windowWidth: document.documentElement.clientWidth,
windowHeight: document.documentElement.clientHeight
}),
mounted() {
window.addEventListener('resize', this.setDimensions);
},
methods: {
setDimensions() {
this.windowWidth = document.documentElement.clientWidth;
this.windowHeight = document.documentElement.clientHeight;
},
}
and don't forget to remove it:
beforeDestroy() {
window.removeEventListener('resize', this.setDimensions);
},

view does not change background image

I have a template in which I call a function and I have a directive element,
.container-wrapper{"ng-controller" => "MovieRowCtrl"}
%i.fa.fa-info-circle{"ng-click" => "updateSelectedMovie(movie)"}
#big-box-container{"ng-if" => "rowActive"}
%movie-details{:movie => "selectedMovie"}
The function is inside a directive,
app.directive('movieDetails', MovieDetailsDirectiveFn)
.controller('MovieRowCtrl', ['$scope', '$rootScope', MovieRowCtrlFn]);
function MovieDetailsDirectiveFn($animate) {
return {
restrict: 'E',
scope: {
movie: '=',
},
templateUrl: '../assets/angular-app/templates/_movie-info.html'
}
}
function MovieRowCtrlFn($scope, $rootScope) {
$scope.updateSelectedMovie = function updateVisibleMovieIndexFn(movie) {
$scope.selectedMovie = movie;
$rootScope.$broadcast('movieRowActivated', {targetScopeId: $scope.$id});
$scope.rowActive = true;
}
}
As you can see I set my MovieRowCtrl as controller for the .container-wrapper.
So when the updateSelectedMovie(movie) function fires it sets the $scope.rowActive to true (showing the element) and it inject the _movie-info.html template inside the %movie-details element.
This works fine.
In that _movie-info.html template I have this,
.movie-background{"ng-style" => "{'background-image':'url(https://image.tmdb.org/t/p/w1280{{movie.backdrop}})'}"}
Which results in,
<div class="movie-background" ng-style="{'background-image':'url(https://image.tmdb.org/t/p/w1280/lXOqBOcx1t5A3YhJEIfJZOkigwH.jpg)'}"
style="background-image: url("https://image.tmdb.org/t/p/w1280/nbIrDhOtUpdD9HKDBRy02a8VhpV.jpg");">
So it creates a ng-style, and a normale style attribute for the element.
The problem is that when I fire the updateSelectedMovie(movie) the ng-style attribute gets updated with a new url, but the style attribut does not get changed.
<div class="movie-background" ng-style="{'background-image':'url(https://image.tmdb.org/t/p/w1280/15PbZtjRJ4zgQA8XS0otL70piQi.jpg)'}"
style="background-image: url("https://image.tmdb.org/t/p/w1280/nbIrDhOtUpdD9HKDBRy02a8VhpV.jpg");">
Any ideas why the ng-style gets updated, but the other style does not?
There is not need to use {{}} inside ng-style, use + for string concatenation while concatenating scope variable inside ng-style expression.
.movie-background{"ng-style" =>
"{'background-image':'url(https://image.tmdb.org/t/p/w1280' + movie.backdrop +')'}"}

How to add stylesheet to toolbar

Using the Firefox Addon SDK, I am creating a toolbar with several buttons and I want to create a mouseover effect for the buttons.
At first I thought to use a mouseover event, but then I would have to create a mouseout event to return it to normal, so I figured the best way would be to use css
In my old XUL version of my addon I was able to attach the stylesheet by linking to it in the XUL code and just add css for my #buttonID, which worked perfectly.
But how do I add the css stylesheet for my toolbar using the Addon SDK?
Here's what I've tried so far (which does not produce any errors), but I think this is just for content; if this is correct, then I'm not sure how to bind to the element:
const { browserWindows } = require("sdk/windows");
const { loadSheet } = require("sdk/stylesheet/utils");
//This is how to load an external stylesheet
for(let w of browserWindows){
loadSheet(viewFor(w), "./myStyleSheet.css","author" );
}
I've also tried this:
var Style = require("sdk/stylesheet/style").Style;
let myStyle = Style({source:'./myStyleSheet.css'});
for(let w of browserWindows){
attachTo(myStyle, viewFor(w))
};
And this:
var { attach, detach } = require('sdk/content/mod');
const { browserWindows } = require("sdk/windows");
var { Style } = require('sdk/stylesheet/style');
var stylesheet = Style({
uri: self.data.url('myStyleSheet.css')
});
for(let w of browserWindows){
attach(stylesheet, viewFor(w))
};
And here is my css:
#myButton:hover{list-style-image(url("./icon-16b.png")!important; }
Tested this in Browser Toolbox:
const { require } = Cu.import("resource://gre/modules/commonjs/toolkit/require.js"); // skip this in SDK
const { browserWindows: windows } = require("sdk/windows");
const { viewFor } = require("sdk/view/core");
const { attachTo } = require("sdk/content/mod");
const { Style } = require("sdk/stylesheet/style");
let style = Style({ source: "#my-button{ display: none!important; }" });
// let self = require("sdk/self");
// let style = Style({ uri: self.data.url("style.css") });
for (let w of windows)
attachTo(style, viewFor(w));
The commented part allows to load from a stylesheet file in the addon data directory.
Notice that you need to import SDK loader to use it in the toolbox.
When in an SDK addon, just use require directly.
NB: there is a difference in spelling: self.data.url vs { uri }
See self/data documentation.
NB2: SDK uses a custom widget ID scheme for toggle and action buttons so your button ID might not be what you expect:
const toWidgetId = id =>
('toggle-button--' + addonID.toLowerCase()+ '-' + id).replace(/[^a-z0-9_-]/g, '');
OR
const toWidgetId = id =>
('action-button--' + addonID.toLowerCase()+ '-' + id).replace(/[^a-z0-9_-]/g, '');
using this code, you should be able to use the mouse over or hover to change how it looks.
#buttonID {
//Normal state css here
}
#buttonID:hover {
//insert css stuff here
}
This goes in the javascript file:
const { browserWindows } = require("sdk/windows");
const { viewFor } = require("sdk/view/core");
const { loadSheet } = require("sdk/stylesheet/utils");
const { ActionButton } = require("sdk/ui/button/action");
var StyleUtils = require('sdk/stylesheet/utils');
var myButton = ActionButton({
id: "mybutton",
label: "My Button",
icon: { "16": "./icon-16.png", "32":"./icon-32.png", "64": "./icon-64.png" },
onClick: function(state) {
console.log("mybutton '" + state.label + "' was clicked");
}
});
//this is how you attach the stylesheet to the browser window
function styleWindow(aWindow) {
let domWin = viewFor(aWindow);
StyleUtils.loadSheet(domWin, "chrome://myaddonname/content/myCSSfile.css", "agent");
}
windows.on("open", function(aWindow) {
styleWindow(aWindow);
});
styleWindow(windows.activeWindow);
And here is the css for that
//don't forget to add the .toolbarbutton-icon class at the end
#action-button--mystrippedadonid-mybuttonid .toolbarbutton-icon,{
background-color: green;
}
There are several gotchas here.
First, as of this posting, you should not use capital letters in the id for the button because they get completely removed - only lowercase letters and hyphens are allowed.
The id of the element is not the same as the id you gave it in the button declaration. See below for how to come up with this identifier.
To specify content in the url for the stylesheet file (in the loadSheet function call) you will also need to create a chrome.manifest in the root of your addon folder, and put this in it: content spadmintoolbar data/ where "data" is the name of a real directory in the root folder. I needed a data/ folder so I could load icons for the button declarations, but you need to declare your virtual directories in chrome.manifest which jpm init does not do for you.
How to get the element id for your css file:
The easy way to get the id for your button element for use in an external style sheet is by testing your addon and then using the browser-toolbox's inspector to locate the element, whence you can fetch the id from the outputted code.
However, if you want to figure it yourself, try this formula.
[button-class] = the sdk class for the button. An Action Button becomes action-button
[mybuttonid] = the id you gave the button in the sdk button declaration
[myaddonname] = the name you gave the addon in it's package.json file.
[strippedaddonid] = take the id you assigned the addon in the package.json file, and remove any # symbol or dots and change it to all lowercase.
Now put it all together (don't include the square brackets):
`#[button-class]--[strippedaddonid]-[mybuttonid]]`
An example: action-button--myaddonsomewherecom-mybutton
Really simple isn't it?!
credit for the stylesheet attach code goes to mconley

Export Html Table to excel and keep css styles

I'm using excel web queries to export an html table (mvc view) to excel. How do I get it to carry across the css styles? If I set class="redLabel" it doesn't interpret that and make the label red. I have to use inline styles in my table for this to work. Any ideas?
As far as I know, most Office programs do NOT support included styling, but only inline styling.
It's likely that you'll be required to include your styling inline (exporting sucks, almost like mail styling).
Excel does support using css styling, but only if there is one class on the element. If there are multiple classes then it will not do any style on the element, see CSS style class not combining in Excel
Having said that, this is the code I put together to grab all the styles on a page and export an HTML table. It's a brute force, grab everything approach, but you could probably pair it down if you know the specifics. The function returns a jQuery Promise. From that you can do whatever with the result.
function excelExportHtml(table, includeCss) {
if (includeCss) {
var styles = [];
//grab all styles defined on the page
$("style").each(function (index, domEle) {
styles.push($(domEle).html());
});
//grab all styles referenced by stylesheet links on the page
var ajaxCalls = [];
$("[rel=stylesheet]").each(function () {
ajaxCalls.push($.get(this.href, '', function (data) {
styles.push(data);
}));
});
return $.when.apply(null, ajaxCalls)
.then(function () {
return "<html><style type='text/css'>" + styles.join("\n") + "</style>\n" + table.outerHTML + "</html>";
});
}
else {
return $.when({ owcHtml: table.outerHTML })
.then(function (result) {
return "<html>" + result.owcHtml + "</html>";
});
}
}
You can export table with outer css style. Here is my solution declare a document template:
var e = this;
var style = "<style></style"; //You can write css or get content of .css file
e.template = {
head: "<html xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:x=\"urn:schemas-microsoft-com:office:excel\" xmlns=\"http://www.w3.org/TR/REC-html40\"><head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets>",
sheet: {
head: "<x:ExcelWorksheet><x:Name>",
tail: "</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet>"
},
mid: "</x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]-->>"+style+"</head><body>",
table: {
head: "<table>",
tail: "</table>"
},
foot: "</body></html>"
};

Resources