Change after property in ng-style without using ng-class - javascript

So I'm trying to create a directive for a some kind of stepper arrow progress bar.
Please see this codepen to understand what I'm talking about. (Note that i wrote the params in the function scope to have an easier read).
The problem I am facing now, is that I wanna pass the colors as param to my directive and I need to apply the colors to both the class and the :after property.
I use that sample to change the background-color of the block-head class, using ng-style. The ng-class I use is to get plain start and end.
<div ng-repeat="element in elements"
class="block-head"
ng-class="{'block-head-first': $first, 'block-head-last': $last}"
ng-style="{'width' : selectedKey === element.key ? 'calc(100% - ' +
widthCalc + 'px)' : '',
'background-color': getColor($index)}">
$scope.widthCalc = ($scope.elements.length - 1) * 26
$scope.getColor = function($index) {
if ($scope.elements[$index].key === $scope.selectedKey)
return $scope.colors['current']
if ($scope.elements[$index].key < $scope.selectedKey)
return $scope.colors['success']
if ($scope.elements[$index].key > $scope.selectedKey)
return $scope.colors['disable']
}
Below is the sample of code I wanna change with ng-style (I set it to lightblue so you understand visually what i'm trying to change).
.block-head:after {
color: lightblue;
I thought of two potential fixes but I have no idea on how to do them. First would be to 'heritate' the color value from the parent in background-color in pure css (not even sure that it is possible ?). Second would be to create classes in my js code and use those classes using ng-class.
All the related questions (here, and here) always advice to use ng-class, but I see no obvious fix with it on my case.

Related

I want to change ng-style multiple times in a JS function

My HTML is:
<nav id="card-set-menu-nav" ng-style="cardSetMenuNavStyle">
...
</nav>
And my Javascript code using AngularJS is like:
$scope.openCardSetMenu = function(cardSet) {
$scope.cardSetMenuNavStyle = {'transition':'0.25s', 'left':'100%'};
$scope.cardSetMenuNavStyle = {'transition':'0.25s', 'left':'50%'};
};
I want to implement simple side menu by changing $scope.cardSetMenuNavStyle variable.
HTML element card-set-menu-nav will be put at left:100% then be pulled out to left:50% like.
But it does not work. It does not move at all after the first unfolding... Maybe transitions are ignored because the final result is the same?
How can I apply multiple CSS transitions on an HTML element?
Add:
Considering the transition time, it seems like only the last transition is applied.
Overwriting a property with two different values one line after the other will not do you any good. Only the last one assigned will have any effect.
If you want to apply one style change, and then apply another 0.25s later, you can inject the $timeout service and use it:
$scope.openCardSetMenu = function(cardSet) {
$scope.cardSetMenuNavStyle = {'transition':'0.25s', 'left':'100%'};
$timeout(function () {
$scope.cardSetMenuNavStyle = {'transition':'0.25s', 'left':'50%'};
}, 250);
};

Parameterize jQuery addClass?

Is it somehow possible to parameterize the jQuery addClass() method?
Like, having a css class with a color property which is set when the addClass() method is called?
I hope that makes sense as I am very new to JavaScript and CSS. If it's of importance, I'm working on extending the MediaWiki VisualEditor. There this method is used to immediatly show/render changes made in the editor. But I couldn't find an example which would require parameterization.
If it's not possible, I'd love to know how to do it.
If it's not, maybe someone can suggest how to realize what I want another way?
Edit:
That's the current state:
When I add some annotation to the text, let's say a languageAnnotation, this is called:
this.$element
.addClass( 've-ce-languageAnnotation' )
.addClass( 've-ce-bidi-isolate' )
.prop( {
lang: this.model.getAttribute( 'lang' ),
dir: this.model.getAttribute( 'dir' ),
title: this.constructor.static.getDescription( this.model )
} );
This is ve-ce-languageAnnotation:
.ve-ce-languageAnnotation {
border-bottom: 1px dashed #ccc;
background-color: #ebf3f5;
}
This is ve-ce-bidi-isolate:
.ve-ce-bidi-isolate {
unicode-bidi: isolate;
unicode-bidi: -moz-isolate;
unicode-bidi: -webkit-isolate;
}
I interpreted this as the prop() function setting some kind of parameter. So this is what I tried for my textColor annotation:
this.$element
.addClass( 've-ce-textColorAnnotation' )
.prop( {
color: this.model.getAttribute( 'style' ),
title: this.constructor.static.getDescription( this.model )
} )
;
With ve-ce-TextColorAnnotation:
.ve-ce-textColorAnnotation {
color: red;
}
This always produces red. When I try to enter something else then a legit color, nothing happens.
Edit2: I guess one option would be to create a class for each possible color, and adding the right class depending on the parameter? Like this:
var color = this.model.getAttribute('style');
if (color == 'blue') {
this.$element.addClass( 'blueText' )
} else if (...
but that doesn't look like a really good idea.
Edit 3: According to the top answer in this question, what I want is not possible - but I can directly apply an attribute without using classes by using this.$element.css('attr', 'value'). I guess I can use this for what I need.
It appears you simply want to set a color, rather than add a class. Classes in HTML can be used for stylization or DOM navigation, however in your case you simply want to apply a different color to an element. You don't need to use classes for that, especially if the colors are dynamic.
What you want to do is call jquery's .css() method. It can be used with a single argument like so:
element.css({
'color': 'black',
'height': '100px'
});
or several, if you only want to edit a single property:
element.css('color', 'black');
Without using jQuery, you could also do this:
element.style.color = 'black';
What can you do in a simple way. Let's say you have a drop down from which you chose the colors. On the value attribute of the option you have blueText for blue, redText for red and so on for each color you want.
Then on the code you can get the value. You can see here how to get the value then you have the classes in CSS like redText, blueText and so on.
When the user clicks on the option you catch the event and do this simple pice of code:
this.$element.addClass( 'text that you got from value attribute' )
You can of course remove the classes before you do the add.

Polymer, evaluate element based off object

I am using the tile example from polymers neon elements - and I am trying to make each expanded tile unique. My first try on how to do this was to pass a string in with the grid items like
{
value: 1,
color: 'blue',
template: 'slide-1'
}
And have that element be evaluated when rendered in a new element something like this. (this is the card template itself)
<template>
<div id="fixed" class$="[[_computeFixedBackgroundClass(color)]]"></div>
<div id="card" class$="[[_computeCardClass(color)]]">
<[[item.template]]></[[item.template]]>
</div>
This does not work - however I am wondering if there is some way to do this so I can load custom elements for the content of each card. For reference -https://elements.polymer-project.org/elements/neon-animation?view=demo:demo/index.html&active=neon-animated-pages , it is the grid example and I am trying to replace the content of each card once it is clicked on ( the fullsize-page-with-card.html, here is all the html for it - https://github.com/PolymerElements/neon-animation/tree/master/demo/grid ). Is this the wrong way of approaching this? Or maybe I have some syntax wrong here. Thanks!
Edit : OK, So I can send it through if i add it to the click to open the card like so
scope._onTileClick = function(event) {
this.$['fullsize-card'].color = event.detail.data.color;
this.$['fullsize-card'].template = event.detail.data.template;
this.$.pages.selected = 1;
};
and in the card's properties like so
template: {
type: String
},
So I can then evaluate it as [[template]] , however - the question still remains how to call a custom element (dynamically) using this string. I could pass a couple of properties and fill in a card or form so they are unique, but i think I would have much more creative freedom if I could call custom elements inside each card.
I have an element that allows referenced templates. There are a couple of others other there, but this one also allows data bindings to work: https://github.com/Trakkasure/dom-bindref

NG Style Failing to automatically bind to page

I'm trying to make a page with two sections, which can be slid back and forth horizontally to take up different relative widths on the page. The idea was to track the percentile width of the (to-be) draggable bar separating the two panes/sections, and use ng_style to automatically update the widths of the two "panes" in relation to where that bar is dragged.
The following is in a Rails app, with integrated Angular. The Angular's loading just fine -- no errors, and the rest is all working -- and the ng_style is being loaded from the Angular controller when the page first loads up -- but it's not changing when I attempt to drag the spacer in between the two "panes", as it's supposed to.
Here's a simplified version of my HAML (sorta like Jade. Just indented HTML):
#full-page.fluid{ ng_controller: "ExerciseCtrl", ng_mousemove: 'updateSidebarWidth($event)', ng_mouseup: 'untrackMouseMove()', ng_cloak: true }
.spacer
.fixed-section-container
.exercise-show
%div
.sidebar-section{ ng_style: '{{ sidebarWidthStyle }}' }
.sidebar_header
.sidebar
%div{ markdown: #exercise.body }
.sidebar-toggle{ ng_mousedown: 'trackMouseMove()' }
.work_area{ ng_style: '{{ workAreaWidthStyle }}' }
And here are the relevant lines in my (Coffeescript) Angular Controller.
$scope.sidebarWidth = 35
$scope.trackingMouse = false
$scope.trackMouseMove = -> $scope.trackingMouse = true
$scope.untrackMouseMove = -> $scope.trackingMouse = false
$scope.updateSidebarWidth = (event) ->
if $scope.trackingMouse
pageWidth = $('.emelyn-layout.middle.fluid').width()
x_percent = (event.pageX * 100) / pageWidth
x_percent = Math.max( Math.min(100, x_percent), 0 )
$scope.sidebarWidth = x_percent
$scope.workAreaWidthStyle = { width: "#{99 - $scope.sidebarWidth}%", marginLeft: "#{$scope.sidebarWidth + 1}%" }
$scope.sideBarWidthStyle = { width: "#{$scope.sidebarWidth}%" }
In other words, I have this .sidebar-section on the left, then a .sidebar-toggle (just a vertical bar), which should be draggable (which causes the width styles to change, once I get this working), and then the .work-area, which is resized, along with the .sidebar, on drag of the toggle.
The issue is that, although the ng_styles are loaded on page load, and although the ng_style values visibly change when I inspect the page and drag the toggle bar, the ng_style changes aren't propagating to the style attributes of the given elements.
In other words, when I inspect the element, I see something like this:
<div class="work_area" ng_style="{ 'width':'48.142857142857146', 'marginLeft':'51.857142857142854' }">
I took a look at this post and tried wrapping updates to the styles in a $scope.$watch, but that didn't change any of the above behavior at all, and it seems wrong to me -- the docs on ng_style suggest to me that the way I'm using it should be effectively correct -- as in, Angular handles the binding for you, without your needing to explicitly tell it when to update the DOM jQuery style.
Any ideas what I'm doing wrong and how to fix it? (Or what might be a better or easier way of doing the above?)
Thanks, and please let me know if you'd like to see any other files or anything,
Sasha
ngStyle works a little differently than what you have. It is evaluated as is, no need for {{}} to point to a $scoped variable.
#full-page.fluid{ ng_controller: "ExerciseCtrl", ng_mousemove: 'updateSidebarWidth($event)', ng_mouseup: 'untrackMouseMove()', ng_cloak: true }
.spacer
.fixed-section-container
.exercise-show
%div
.sidebar-section{ ng_style: 'sidebarWidthStyle' }
.sidebar_header
.sidebar
%div{ markdown: #exercise.body }
.sidebar-toggle{ ng_mousedown: 'trackMouseMove()' }
.work_area{ ng_style: 'workAreaWidthStyle' }
When you use {{}} it evaluates that to a string and then runs it through ngStyle. ngStyle ends up watching a string and not a variable.

How can I implement pseudo-dynamic css?

Im having trouble with managing custom colored elements on the page.
For example, we have 100 navigation squares on the page, each one has its own color, cant think of any way except of creating css classes for each type of color. Which will produce LOTS of css code.
Need some help with this,
Thanks
*added javascript & jquery tags as one of the possible ways of solving this question
Update:
Thanks for responses guys, feeling like I need to get into details.
Im having squared category navigation on my search page, colors can go from server side or can be stored in client's js.
Im getting list of categories from server (lets assume im getting color for each one too)
Then Im building all squares (they are white by default, but on :hover they change their color)
So I would go for such solution:
<ul id="squares">
<li class="greencolor"></li>
<li class="redcolor"></li>
<li class="bluecolor"></li>
</ul>
with css:
#squares li.redcolor:hover{
background:red;
}
#squares li.greencolor:hover{
background:green;
}
#squares li.bluecolor:hover{
background:blue;
}
Hopefully now you can see what I was talking about referring tons of css code for 100 elements.
And yes, I understand that I can go for such solution:
var colorsMap={'redcolor':'red','greencolor':'green'};
$('#squares li').on('hover',function(e){
$(this).css('background-color', colorsMap[$(this).attr('class')];
});
but this doesnt sound as an elegant solution to me and Im trying to find way to make it through css, not inline css changes by js
Although I recommend to use CSS to achieve it, but there's still a solution better than inline style:
var selector = '#squares li'
, css = []
, style = document.createElement( 'style' )
, colorsMap= {
'redcolor': 'red',
'greencolor': 'green',
'bluecolor': 'blue'
}
$( selector ).each( function() {
css.push( selector +
'.' +
// recommand to use data-attr to store color info
// assuming `className == 'bluecolor'`
this.className +
':hover' +
'{' +
'background:' +
colorsMap[ this.className ] +
'}'
)
})
style.textContent = css.join('')
document.head.appendChild( style )
By dynamic insert CSS into <head>, you still get the benefits from normal CSS, demo.
And, you also can generate dynamic CSS file in back-end side, it's more easier to manage colors, by a configuration form or something else.
First,my English is poor(But I'm trying my best to learn).So I can't say that I understand you clearly.But what you say let me think of the chooser.I didn't know if it is you want,but I think it's not a bad idea. Just like these:
$(":header").css("color","#FF00FF");
$("div:contains('test')").css("background","#666600");
$("div:empty").css("background","#888800");
$("div:has(span)").css("background","#008080");
etc.
Their role's I won't say it.I think it nessary for to learn, they are very useful.

Categories

Resources