Angular 2 multiple font colors in a textarea - html

I have a text area with one string binded to it. With the text color as white by default.
<textarea style="background-color: black;color:#fff;" [(ngModel)]="outputText"></textarea>
The bound string contains multiple variables.
return this.outputText = this.test1 + " test1Stat" + this.test2 + " test2Stat" + this.test3 + " test3Stat";
What I want to do is, if test1 is less than 1, it should show "test1 test1Stat" in red, while everything else is in green. Is there a way to do this?

It's not possible to color part of the text in a textarea,
However- you can try to use the 'contenteditable' property instead.
It basically turns your div into a textbox, and you can use html tags and such inside.
.greenText{
color:green;}
div{
border:black solid 1px;
padding:20px;
}
<div contenteditable="true">text text <span class='greenText'>GREEN TEXT</span> more text that you can edit</div>

Related

how to highlight the words which are invalid in input given by a user

how to highlight only the words which are invalid in input given by a user where i can make my custom invalid check function.
e.g
hello this is very good and very nice.
suppose this is the input by the user and suppose i want to highlight "very" and "this" or any other custom word.
I have tried putting html tag inside value but html does not parses inside value attribute of input tag.
Try using variable.split() in reading the input. Store it in array using loop and check for errors and highlight
You cannot simply put html tags in input. To enable "rich text" capabilities, you'll have to use the contenteditable HTML attribute, like so...
const words = [/(very)/gi, /(nice)/gi]
const highlightInput = () => {
const richInput = document.getElementById('rich-input')
let text = richInput.innerText
words.forEach(x => {
text = text.replace(x, '<span class="highlighted">$1</span>')
})
richInput.innerHTML = text
}
document.getElementById('highlight').addEventListener('click', highlightInput)
#rich-input{
border:1px solid #000;
padding: 5px;
}
.highlighted{
color:red;
text-decoration:underline;
}
<div>
<input type="button" value="Highlight!" id="highlight" />
</div>
<label>Enter your text below:</label>
<div id="rich-input" contenteditable="true">Hello this is very good and very nice</div>

angular ngModel style

Is it possible to style the value in the attribute ngModel of an input tag?
Example:
<input class="input" type="text" [(ngModel)] = "myService.text">
Let's say the value of text is '28 packages', can I put 28 in bold?
So if i understand correctly you want to have it bold whenever the value is 28 ?
yes its possible you can use a ng-class with a ternary expression like this
.bold{
font-weight:600;
}
<input type="text" ng-class="myService.text == '28 ? 'bold' : '''" class="input" ng-model="myService.text" />
This is not angular-related rather a CSS related question.
You cannot style only a part of an input in HTML/CSS so you won't be able to do it in angular.
Instead, you can use an input that is hidden behind a div. The idea is that when the user clicks the div, you actually focus the input. When the user types text, you capture the content of the input and fill the div with it, eventually adding <span class"highlight"> around the number of packages.
I prepared you a stackblitz in pure CSS/JS. You can adapt it in angular if you want.
Relevant pieces of code :
HTML :
<span id="hiddenSpan">This is the hidden div. Click it and start typing</span>
<div>
<label for="in">The real input</label>
<input id="in" type="text">
</div>
JS :
const input = document.getElementById('in')
const hiddenSpan = document.getElementById('hiddenSpan')
function onInputChanged() {
let text = input.value
const regex = new RegExp('(\\d+) packages')
let result = regex.exec(text)
if(result) {
hiddenSpan.innerHTML = '<span class="highlight">'+result[1]+'</span> packages'
} else {
hiddenSpan.innerHTML = text
}
}
// Capture keystrokes.
input.addEventListener('keyup', onInputChanged)
// Focus the input when the user clicks the pink div.
hiddenSpan.addEventListener('click', function() {
input.focus()
})
CSS :
#hiddenSpan {
background-color: pink;
}
.highlight {
font-weight: bold;
background-color: greenyellow;
}
Note : the downside is that the blinking caret is not visible anymore. You can take a look at this resource if you want to simulate one.
It is not possible to style certain parts of a text <input> field in bold. However, you can use a contenteditable div instead of a text <input> field. Inside the contenteditable div you can have other HTML tags like <strong> to style certain parts of the text however you like.
I created an Angular directive called contenteditableModel (check out the StackBlitz demo here) and you can use it to perform 2-way binding on a contenteditable element like this:
<div class="input" contenteditable [(contenteditableModel)]="myService.text"></div>
The directive uses regular expressions to automatically check for numbers in the inputted text, and surrounds them in a <strong> tag to make them bold. For example, if you input "28 packages", the innerHTML of the div will be formatted like this (to make "28" bolded):
<strong>28</strong> packages
This is the code used in the directive to perform the formatting:
var inputElement = this.elementRef.nativeElement;
inputElement.innerHTML = inputElement.textContent.replace(/(\d+)/g, "<strong>$1</strong>");
this.change.emit(inputElement.textContent);
You can change the <strong> tag to something else (e.g. <span style="text-decoration: underline"> if you want the text to be underlined instead of bolded).
When performing the formatting, there is an issue where the user's text cursor position will be unexpectedly reset back to the beginning of the contenteditable div. To fix this, I used 2 functions (getOriginalCaretPosition and restoreCaretPosition) to store the user's original cursor position and then restore the position back after the text formatting is performed. These 2 functions are kind of complex and they're not entirely relevant to the OP's question so I will not go into much detail about them here. You can PM me if you want to learn more about them.

CSS background for text only & not parent span/div/body?

I'm not sure this is possible, but i was wondering if it is possible to set a background color for text only, & not the span/div/P tags that contain the text.
EG
This text here...
each character of "this" will be a black background with white text, the 'space' will have the blue background the word "text" will be a black background with white text etc....
Something like what deaf people see on some TV shows - captions...
But I don't want to contain each / every word with a div or span - as that will make the total HTML coding huge...
From what i have gathered / googled, I can set a background for an entire 'container' but not just for "text" in the container.
example: How do I set background color of text only in CSS?
The above sets the whole h1 tag as a green background.
PS - i'm only using 'green' as an example - but i've got other colours in mind, or even pictures as the background. but i want the text content to be visible..
PS, if the above can be done, is it also possible to 'opaque' the text-background ? so the actual / main background is partially visible, but keep the text "solid".
Ive used opaque, but it makes the foreground text opaque (not kept as solid).
This is the solution I found using JavaScript. It is definitely not only CSS, but it's as far as I could get it with minimal code:
Note: check the updated JSFiddles below! http://jsfiddle.net/fq4ez69t/1/
It finds all spaces in your "p" tags (i.e. change this to whatever you need) and substitutes them with a span with class .space so that you can style it in your CSS.
Here's the JS:
var str = document.getElementsByTagName("p")[0].innerHTML;
var newstring = str.replace(/ /g, '<span class="space"> </span>');
document.getElementsByTagName("p")[0].innerHTML = newstring;
Update #1
Just thought of this. Maybe change the getElementsByTagName("p")[0].innerHTML; to something like document.getElementsByClassName('shaded')[i]; and use this class on whatever text you want to look like that. This is done using a for loop like so:
http://jsfiddle.net/fq4ez69t/2/
Just add the class shaded to the text element you want to look like the image above and voila!
var shadedtextblocks = document.getElementsByClassName("shaded");
for(var i = 0; i < shadedtextblocks.length; i++)
{
var str = shadedtextblocks[i].innerHTML;
var newstring = str.replace(/ /g, '<span class="space"> </span>');
shadedtextblocks[i].innerHTML = newstring;
}
Update #2 - Works with background images now.
http://jsfiddle.net/37s7ex2j/
Here's an updated version that works for p and h1 tags and uses jQuery. It won't print backgrounds on top of your background image. It looks much better, but the script is a bit slower. Here's the result:
$('.shadedtext').each(function(){
//FOR P ELEMENTS
var text = $.trim($('p').text()),
word = text.split(' '),
str = "";
$.each( word, function( key, value ) {
if(key != 0) { str += " "; }
str += "<span class='shade'>" + value + "</span>";
});
$('p').html(str);
});
Choosing text in a container
In short: No you can not set the background of only the text in a div, or spesialy choose each color for each word.
What you can do is set the text of each container ofc:
<div class="class"></div>
.class {
//background, can also use rgba(0,0,0,0.5) <- semi transparent black.
background-color: white;
}
But I don't want to contain each / every word with a div or span - as that will make the total HTML coding huge...
Keeping your text inside inline-block elements will keep the selection to some what text only.
Example:
p {
background-color: rgba(5, 5, 5, 0.5);
color: white;
}
p.inline {
display: inline-block;
}
Inline
<p>Lorem ipsum dolar si amet</p>
Inline-block
<br>
<p class="inline">Lorem ipsum dolar si amet</p>
If you want something like subtitles on TV, you can add a text-shadow on your text:
.myTextClassSelector{
text-shadow: green 1px 1px, green -1px 1px, green -1px -1px, green 1px -1px;
}
<div>
<p class="myTextClassSelector">This text here</p>
And this other text here.
</div>

How to create a "placeholder" for DIV that act like textfield?

Div don't have a placeholder attribute
<div id="editable" contentEditable="true"></div>
I want <Please your enter your Name> to show in DIV when the User backspace the whole text in the DIV, or no text on inside, How can I do it?
Here is a pure CSS only solution:-
<div contentEditable=true data-ph="My Placeholder String"></div>
<style>
[contentEditable=true]:empty:not(:focus):before{
content:attr(data-ph)
}
</style>
Here, we basically select all contentEditable <divs> that are empty & blurred. We then create a pseudo element before the CSS selection (the editable div) and fix our placeholder text (specified the data-ph attribute) as its content.
If you are targeting old school CSS2 browsers, change all occurrences of data-ph to title
Correction.......the :empty selector is not supported in IE version 8 and earlier.
What I find in other answers is that when using :not(:focus) pseudo class, I have to click again in order to get the blinking cursor and be able to type. Such issue doesn't happen if I click on an area other than the placeholder.
My workaround is simply removing :not(:focus). Even though in this way the placeholder will still be there after I click on the editable div, I'm able to type no matter where in the div I click, and the placeholder disappears immediately after I type something.
BTW, I inspected YouTube's comment div implementation, seems they are doing the same thing, e.g. #contenteditable-root.yt-formatted-string[aria-label].yt-formatted-string:empty:before
.editableDiv1,
.editableDiv2 {
border-bottom: 1px solid gray;
outline: none;
margin-top: 20px;
}
.editableDiv1[contentEditable="true"]:empty:not(:focus):before {
content: attr(placeholder)
}
.editableDiv2[contentEditable="true"]:empty:before {
content: attr(placeholder)
}
<div class="editableDiv1" contentEditable=true placeholder="If you click on this placeholder, you have to click again in order to get the blinking cursor and type..."></div>
<div class="editableDiv2" contentEditable=true placeholder="Click on placeholder is fine, it'll disappear after you type something..."></div>
You can try this one !
html:
<div contentEditable=true data-text="Enter name here"></div>
css:
[contentEditable=true]:empty:not(:focus):before{
content:attr(data-text) }
check it out (demo)
in HTML
<div id="editable" contenteditable="true">
<p>Please your enter your Name</p>
</div>
in JavaScript
jQuery.fn.selectText = function(){
var doc = document;
var element = this[0];
console.log(this, element);
if (doc.body.createTextRange) {
var range = document.body.createTextRange();
range.moveToElementText(element);
range.select();
} else if (window.getSelection) {
var selection = window.getSelection();
var range = document.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
}
};
$("#editable").click(function() {
$("#editable").selectText();
});
jsFiddle

Is it bad to put <span /> tags inside <option /> tags, only for string manipulation not styling?

I would like to make groups of the text content of an <option /> tag. Say I have the following: <option>8:00 (1 hour)</option>, the time pattern 8:00 can be modified, then the text in parenthesis (1 hour) can also be modified.
I was thinking of doing something like
<option>
<span>8:00</span>
<span> (1 hour)</span>
</option>
Is it bad to put <span /> tags inside <option /> tags, only for string manipulation not styling?
From the HTML 5spec:
Content model:
If the element has a label attribute and a value attribute: Nothing.
If the element has a label attribute but no value attribute: Text.
If the element has no label attribute and is not a child of a datalist element: Text that is not inter-element whitespace.
If the element has no label attribute and is a child of a datalist element: Text.
So depending on context there are two things that you can put inside an <option> — text or nothing at all — you may not put a <span> or any other element there.
From the HTML 4.01 spec:
<!ELEMENT OPTION - O (#PCDATA) -- selectable choice -->
(Even the HTML 3.2 and HTML 2 specs say: <!ELEMENT OPTION - O (#PCDATA)*>)
An option element cannot have any child elements. So yes, it is bad.
You can use a Javascript plugin to overcome this limitation. For example jQuery plugin "Select2" Select2 plugin homepage. I use it in a couple of my projects and think that it's pretty flexible and convenient.
There are a number of them, but they do quite same thing - convert traditional <select> into <div> blocks with an extra functionality.
The option element
Content model: Text
No, it’s not ok. Consider keeping the values around in your script so you can recompose them when necessary.
You're better off using an HTML replacement for your <select> if you want to do this.
As established by other people, and I have tried with <b> and other tags, <option> does not take tags within it.
What you can do, since you cannot use <span> inside an <option> tag,
You can use the index number to extract the text via
document.getElementById(selectid).options[x].text where x is the relevant index, as a variable.
Then what you do is use the " (" to split the variable into the time, and remove the last character as well which removes the ")"
Sample:
<script type="text/javascript">
function extractSelectText()
{
var text = document.getElementById("main").options[1].text
/*
var tlength = text.length
var splitno = tlength - 1
var text2 = text.slice(0, splitno)
var textArray = text2.split(" )")
var time = textArray[0]
var hours = textArray[1]
}
</script>
Changing it is much simpler:
<script type="text/javascript">
function changeSelectText()
{
/* add your code here to determine the value for the time (use variable time) */
/* add your code here to determine the value for the hour (use variable hours) */
var textvalue = time + " (" + hours + ")"
document.getElementById("main").options[1].text
}
</script>
If you use a for function you can change each value of the select replacing 1 with 2, 3 and so on, and put a set interval function to constantly update it.
One option for editing would be to use some fancy pattern matching to update the content. It will be slower and more resource intensive, and depends on how regular the format is, but doesn't require any HTML modifications. My concern, however, would be on accessibility and the user experience. Having values change is hard for screen reader software to pick up, and it may also confuse other users.
It is not an answer, but may be it will help sombody, it is possible to mimic select with details tag. This example is not complete, I used javascript to close list on click
const items = document.querySelectorAll(".item");
// Add the onclick listeners.
items.forEach(item => {
item.addEventListener("click", e => {
// Close all details on page
closeList(item);
});
});
function closeList(item) {
document.querySelectorAll("details").forEach(deet => {
if (deet != this && deet.open) {
deet.open = !open;
console.log(item);
}
});
}
details {
border: 1px solid #aaa;
border-radius: 4px;
}
summary {
padding: .5em 0 .5em .5em;
font-weight: bold;
}
details[open] {
}
details[open] .item {
cursor: pointer;
padding: .5em 0 .5em .5em;
border-top: 1px solid #aaa;
}
details[open] .item:hover{
background-color: #f1f1f1;
}
details[open] .title{
padding: .5em 0 .5em .5em;
border-top: 1px solid #aaa;
}
<details>
<summary>Select your choice</summary>
<div class='title'>
This is attempt to mimic native <code>select</code> tag with html for <code>option</code> tag
</div>
<div class='item'>item 1</div>
<div class='item'>item 2</div>
<div class='item'>item 3</div>
</details>