I have an idea to change the theme on my web page. Here is my CSS that I am using:
html.darkBlue {
.block-content.light-tint-bg {
background: #fefefe;
border: 1px solid #777777;
color: #7b7b7b;
}
}
html.black {
.block-content.light-tint-bg {
background: #333333;
border: 1px solid #111111;
}
}
The idea is that I add a class to the HTML and depending on the class that is used it will use one theme or another.
But with Angular how could I make it switch? I was thinking of having an address kind of link but I am not sure how to switch between two classes?
I use a similar approach to #Davin Tryon, except like like this:
In the controller:
$scope.applied = false;
Then in the ng-class
ng-class="{true: 'applied', false: 'notApplied'}[applied]"
So based on the value of applied being true or false, it will apply the value of the property in the expression applied when true, and notApplied when false.
Edit:
Ok based on your comment:
http://jsfiddle.net/muLPT/
<div ng-app ng-class="background">
Hello World
<input type="button" ng-click="background = 'black'" value="black">
<input type="button" ng-click="background = 'red'" value="red">
<input type="button" ng-click="background = 'blue'" value="blue">
</div>
.black {
background: black;
}
.red {
background: red;
}
.blue {
background: blue;
}
This should do what you want.
Basically just changes the value of 'background' class to what ever value was clicked.
The sample is done on a div since I can't demo it on html from jdfiddle. Should work the same if its applied to html
You can use ng-class. Here are the docs.
ng-class allows you to resolve the class using an expression.
The example here shows usage:
<p ng-class="{applied: 1 == 1, notApplied: 1 == 0}">Example</p>
The expression 1 == 1 will resolve to true and the class 'applied' will be added to the class attribute.
In order to handle a click and toggle the class, you would create a scoped variable. For example this will toggle a clicked field that will add/remove the class:
<div ng-click="clicked = !clicked" ng-class="{black: clicked, darkBlue: !clicked}"></div>
Related
I'm investigating the use of Quill for a project, and I need to know if it's possible to create a custom format/blot with more complexity than a single element and a single parameter.
An example of one of the layouts I want would be:
<span class="format-container">
<span class="format-info" data-attr="param 1 (non-displayed)">
param 2 (displayed to user -- click to invoke application UI to edit)
</span>
<span class="format-content">
User's text/child elements go here
</span>
</span>
In all cases I'm looking into, the custom formats are of inline scope and still have a single parent container and a single place for the child content to go.
Custom formats in Quill don't seem to be very well documented at the moment. I poked around in the sources and was able to figure out that this most likely isn't possible in 0.20.1. However, I feel like it could be doable in the 1.0.0 beta w/ Parchment, I'm just not sure on the specifics of what I'd actually need to write.
So is this possible in 1.0.0? If so, how could it be done?
EDIT: This is what I'm going for:
So, I figured out how to do this in the end with minimal effort. It involves defining a new blot type for Quill 1.3 or greater, the same code should work on older versions however is untested.
See the code snippet for a working example. The crux is to extend the existing Embed blot 'blots/embed' and define your own toolbar handler to inject arbitrary DOM node instances.
// utility function used to inherit non prototypical methods/properties
function extend(target, base) {
for (var prop in base) {
target[prop] = base[prop];
}
}
// definition of a custom Blot.
(function(Embed) {
'use strict';
function Span() {
Object.getPrototypeOf(Embed).apply(this, arguments);
}
Span.prototype = Object.create(Embed && Embed.prototype);
Span.prototype.constructor = Span;
extend(Span, Embed);
Span.create = function create(value) {
return value; // expects a domNode as value
};
Span.value = function value(domNode) {
return domNode;
};
Span.blotName = 'span';
Span.tagName = 'SPAN';
Span.className = 'complex';
Quill.register(Span, true);
})(Quill.import('blots/embed')); // import the embed blot. This is important as this is being extended
// custom handler for the toolbar button
var handler = function() {
var complexSpan = document.getElementById('complextype').firstElementChild.cloneNode(true);
var selection = quill.getSelection();
quill.insertEmbed(selection.index, 'span', complexSpan);
}
// instantiate quill. Note that modules.toolbar.handlers has a 'span' handler. Quill parses this from // the class on the button in the toolbar markup: 'ql-span' this is 'ql-' + blotName
var quill = new Quill('#editor', {
modules: {
toolbar: {
container: '.toolbar',
handlers: {
'span': handler
}
}
},
theme: 'snow'
});
:root {
--complex-bgcolor: #767676;
--font-color: #FFFFFF;
}
html {
font-size: 10px;
}
button.ql-span {
width: 15rem !important;
}
.complex {
border-radius: 1rem;
border: 0.2rem solid black;
margin: 0.3rem;
}
.inner {
border-radius: 1rem;
background: var(--complex-bgcolor);
color: var(--font-color);
padding-left: 0.6rem;
padding-right: 0.6rem;
}
.formatting {
font-weight: bold;
font-style: italic;
text-decoration: underline;
}
.nested {
margin-left: 0.3rem;
margin-right: 0.3rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/quill/1.3.1/quill.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/quill/1.3.1/quill.snow.css" />
<div id="wrapper">
<div id="toolbar" class="toolbar">
<span class="ql-formats">
<button class="ql-bold"></button>
<button class="ql-italic"></button>
<button class="ql-underline"></button>
</span>
<span class="ql-formats">
<button class="ql-span">Complex Span Type</button>
</span>
</div>
<div id="editor">Lorem Ipsum
<span contenteditable="false">
<span class="complex" spellcheck="false">
<span class="inner">Format applied</span>
<span class="nested">More text</span>
<span class="formatting">with formatting</span>
<span class="nested">dolor</span>
</span>
</span> sit amet
</div>
</div>
<div id="complextype" style="display:none;">
<span contenteditable="false"><span class="complex" spellcheck="false"><span class="inner">Format applied</span><span class="nested">More text</span><span class="formatting">with formatting</span><span class="nested">dolor</span></span></span>
</div>
Documentation and guides are still being written but a good place to look is how existing custom formats are implemented. The formula format in particular seems very similar to your use case.
My code looks like this:
<div class="block-border"
data-ng-show="qty > 0">
xxx
</div>
I know there have been a lot of changes with Animation in AngularJS. Can someone tell me the easiest way for me to make it take 500ms to show and 50ms to hide the xxx when the value of qty changes. Note that I am using the very latest AngularJS.
Reference angular-animate.js
Add ngAnimate as a dependent module:
var app = angular.module('app', ['ngAnimate']);
Pick a name for your transition, for example 'fade', and then define the appropriate CSS classes based on the naming convention described in the documentation:
.fade.ng-hide {
opacity: 0;
}
.fade.ng-hide-remove,
.fade.ng-hide-add {
display: block !important; /* or inline-block, as appropriate */
}
.fade.ng-hide-remove {
transition: all linear 1000ms;
}
.fade.ng-hide-add {
transition: all linear 500ms;
}
Add the class to your element:
<div class="block-border fade" ng-show="qty > 0">
Demo: http://plnkr.co/edit/HWi0FfDOsHeSOkcrRtN2?p=preview
I couldn't get the accepted answer to work, but the following did work (taken largely from this ng-nuggets post):
.fade {
transition: all linear 500ms;
opacity: 1;
}
.fade.ng-hide {
opacity: 0;
}
and then my HTML element which I wanted to fade in and out looked something like this:
<span data-ng-show="copyLinkClicked" class="fade">some text here</span>
As #MichaelNguyen mentioned, Bootstrap does appear to have a style already called fade, and we are using Bootstrap in our application, yet the above styles worked nonetheless. If you already have a style named fade, then change the name to something unique before using the above code.
If you want to fade in using ng-if as a boolean angular has some nice documentation here https://docs.angularjs.org/api/ngAnimate . I used ng-if for my fading purposes here's an example below:
form.html
<form name="exampleForm" ng-submit="submit()">
<input type="email" placeholder="Email Address" ng-model="email" required>
<input type="text" placeholder="Name" ng-model="name" required>
<input class="invalid-btn" ng-if="exampleForm.$invalid" type="submit" value="Invalid" />
<input class="valid-btn" ng-if="exampleForm.$valid" type="submit" value="Valid">
</form>
form.css
/* css for button that will show when form is invalid */
.invalid-btn {
border: 1px solid #222;
width: 100px;
height: 50px;
color: #222;
background: #fff;
}
.invalid-btn.ng-enter {
opacity: 1;
}
/* The finishing CSS styles for the enter animation */
.invalid-btn.ng-enter.ng-enter-active {
opacity: 0;
}
.valid-btn {
width: 100px;
height: 50px;
background: #F26623;
color: #fff;
}
/* The starting CSS styles for the enter animation */
.valid-btn.ng-enter {
transition:0.5s linear all;
opacity: 0;
}
.valid-btn.ng-enter-stagger {
/* this will have a 100ms delay between each successive leave animation */
transition-delay: 0.3s;
/* As of 1.4.4, this must always be set: it signals ngAnimate
to not accidentally inherit a delay property from another CSS class */
transition-duration: 0s;
}
/* The finishing CSS styles for the enter animation */
.valid-btn.ng-enter.ng-enter-active {
width: 100px;
height: 50px;
background: #F26623;
color: #fff;
opacity:1;
}
The way this works is if you want to fade in a button with a different color or text and different text color you can fade in a button when the form is filled out and valid and the invalid button will fade out leaving only one button depending on the state of the form. Kind of a hack but it works and looks smooth. I had to set a delay using .ng-enter-stagger because loading the animations at the same time was causing the buttons to blink and jump and not animate smoothly. So in this case we let invalid button hide first then load valid button when form is valid and all input fields have been filled out correctly.
So I have two elements that are exclusive:
<span>foo</span>
<span>bar</span>
And I added ngShow and ngHide to them:
<span ng-show="fooTime">foo</span>
<span ng-hide="fooTime">bar</span>
But now when these render, there is a split second where they both show.
How can I make them show/hide at the same time?
Use a ngSwitch rather than an ngShow/ngHide:
<span ng-switch="fooTime">
<span ng-switch-when="true">foo</span>
<span ng-switch-when="false">bar</span>
</span>
Why?
When using the separate ngShow/ngHides, each element is getting a separate $watch which execute asynchronously leaving the potential for a gap between the events. By using ngSwitch, only one $watch is setup so they must render at the same time.
How I got to ngSwitch?
On my first attempt, I realized the watches were not tied together, so I resorted to letting CSS tie the changes together:
<style>
[first] .fooTime {
display: inline;
}
[second] .fooTime, [first] {
display: none;
}
</style>
<span ng-class="{'fooTime':fooTime}">
<span first>foo</span>
<span second>bar</span>
</span>
But ngSwitch is much more clean.
Edit:
It seems ngSwitch triggers enter and leave animations so if you are using ngAnimate, there is a default of a .2 second transition. I haven't found a way around this yet.
You can solve this problem pretty elegantly with some CSS.
*[ng-switch] *[ng-switch-when] + *[ng-switch-when],
*[ng-switch] *[ng-switch-when] + *[ng-switch-default] {
display: none;
}
This uses the wildcard selector (*) and attribute selector for ng-switch-when to make this a general solution that should work in any instance where ng-switch is used.
Upvoted and commented on #eternalmatt's answer ... here is my solution based on the css part of his solution. In my experience ng-swtich will not solve this problem. I am using scss but you can convert scss to css here http://www.sassmeister.com/. The template of my button directive that toggles button text and ajax spinner based on the value of showSpinner.
template
<button class="fin-button no-outline" ng-class="{disabled: state==='disabled'}" ng-click="action()">
<span ng-class="{'showSpinner': showSpinner}">
<span class="text-first" fin-button-text>{{text}}</span>
<span class="glyphicon glyphicon-repeat spinner" fin-button-spinner></span>
</span>
</button>
scss
.fin-button {
[fin-button-text] {
display: inline;
}
[fin-button-spinner] {
display: none
}
.showSpinner {
[fin-button-text] {
display: none;
}
[fin-button-spinner] {
display: inline;
}
}
}
css .. generated from conversion via the above link
.fin-button [fin-button-text] {
display: inline;
}
.fin-button [fin-button-spinner] {
display: none;
}
.fin-button .showSpinner [fin-button-text] {
display: none;
}
.fin-button .showSpinner [fin-button-spinner] {
display: inline;
}
and is here be dragons comment that I have above the scss in my code
// .... HERE BE DRAGONS ... ///
// The following is used to hide show the spinner or the
// button text. Needs to be done like this because ng-hide, ng-show,
// ng-if, and ng-switch all put seperate watches even if you are conditioning
// on the same vairable ... see this SO // http://stackoverflow.com/questions/20341288/how-do-i-ngshow-and-nghide-two-different-elements-at-the-same-time-with-angularj
This is very straightforward but I am not able to change the class.
I am basically verifying if the date is in correct format (DD-MMM-YYYY hh:mm:ss).
<input type="text" style="width : 80%" ng-model="startTime" ng-class="{invalid: !isValid ,valid: isValid}" />
where isValid is a scope variable which evaluates to true and false. The css class is not applied.
Here is the plnkr.
It is working. Inspect the element. Your bootstrap classes are overwriting it. Try this:
.invalid {
background-color: #FA787E !important;
}
.valid {
background-color: #78FA89 !important;
}
I want to change the class of one div while hovering over another div using AngularJS directives. Here is what I have so far http://jsfiddle.net/E8nM5/38/
HMTL
<div ng-controller="Ctrl" ng-app>
<div ng-class="my-class">This div will change class when one hovers over bottom DIV </div>
<br/>
<div class="hover-div" ng-mouseenter="my-class = 'highlight'" ng-mouseleave="my-class = 'lowlight'">HOVER OVER ME TO CHANGE THE UPPER DIV's CLASS</div>
</div>
CSS
div.highlight {
padding: 10px;
background: red;
color: white;
}
div.lowlight {
padding: 10px;
background: blue;
color: white;
}
div.hover-div {
padding: 10px;
background: green;
color: white;
}
JS
function Ctrl($scope){
}
Any ideas?
Change my-class to myclass (i.e. the dash causes problem).
<div ng-controller="Ctrl" ng-app>
<div ng-class="myclass">This div will change class when one hovers over bottom DIV </div>
<br/>
<div class="hover-div" ng-mouseenter="myclass = 'highlight'" ng-mouseleave="myclass = 'lowlight'">HOVER OVER ME TO CHANGE THE UPPER DIV's CLASS</div>
</div>
Updated: the reason my-class isn't allowed in the expression is because AngularJS treats the dash as minus symbol and tries to parse it that way. Apparently, it can't parse the statement my - class = 'highlight'. Unfortunately, after reading AngularJS parser code, I can't find a way to "help" it distinguish between dash and minus.
You need to remove the hyphen from my-class so it will work properly in your Controller. Other than that it looks like you have it mostly done. Here's a little snippet - I also added it as text in the div so you can see it change
Your HTML File:
<div class="{{myClass}}"> {{myClass}} </div>
<div class="hover" style="height:50px; width:50px; border:1px solid black;" ng-mouseleave="myClass='test'" ng-mouseenter="myClass='hola'"> </div>
Controller
function Ctrl($scope){
$scope.myClass="test";
}