Vue 2 raw HTML bind to textarea - html

I'm creating an online text editor. I need to be able to get the users text from the textarea's tag, manipulate this text and bind it back to the textarea, but with HTML in it.
Example:
<textarea v-model="someText"></textarea>
Where someText is set to:
someText: '<b>bold</b>.. not bold'
and should display like:
bold.. not bold
instead of: <b>bold</b>.. not bold
I have a feeling this isn't possible with the textarea tag, but what would be a way to do this?

Typically you would use v-html, but you are correct, inside <textarea> the value will be raw, not processed (will not be bold).
To achieve what you want, maybe you could leverage the contenteditable property to create a <html-textarea>, as below.
Vue.component('html-textarea',{
template:'<div contenteditable="true" #input="updateHTML"></div>',
props:['value'],
mounted: function () {
this.$el.innerHTML = this.value;
},
methods: {
updateHTML: function(e) {
this.$emit('input', e.target.innerHTML);
}
}
});
new Vue({
el: '#app',
data: {
message: 'H<b>ELLO</b> <i>editable</i> Vue.js!'
}
});
div[contenteditable] { border: 1px solid lightblue; }
<script src="https://unpkg.com/vue"></script>
<div id="app">
<html-textarea v-model="message"></html-textarea>
<hr>
<div>
Raw message:
<pre>{{ message }}</pre>
</div>
</div>

I'd have done it this way.
<template>
<div id="app">
<form name="yourform">
<textarea v-model="someText"></textarea>
</form>
</div>
</template>
<script>
export default {
name: 'app',
data () {
return {
someText: 'bold'
}
}
}
</script>
<style scopped>
textarea
{
font-weight:bold;
}
</style>

Related

Display FontAwesome icon in Vue 3 with JavaScript array

I am trying to display FontAwesomeicon
<font-awesome-icon icon="fa-solid fa-shop" />
with JavaScript array to be dynamic but it's not working it displays as text
<div class="aboutme-card" v-for="(item,index) in servicesArr" :key="index">
<div class="service-card-icon">{{item.icon}}</div> <!--but its display as text not as icon svg-->
<div class="service-card-title">{{item.title}}</div>
<p class="service-card-desc">{{item.description}}</p>
</div>
<script>
export default {
data() {
return {
servicesArr: [
{
icon: `<font-awesome-icon icon="fa-solid fa-shop" />`,
title: "E-commerce",
}
]
}
}
}
</script>
Isn't something like this conceivable in your case?
<template>
<div class="aboutme-card" v-for="item in servicesArr" :key="item.icon">
<div class="service-card-icon">
<font-awesome-icon :icon="item.icon" />
</div>
</div>
</template>
<script>
export default {
data() {
return {
servicesArr: [
{
icon: "fa-solid fa-shop",
title: "E-commerce",
}
]
}
}
}
</script>
Even if v-html exists, it's usually not the way to go.
Especially in such a simple use-case where dynamic props are totally fine.
Overall, I still recommend that solution for overall ease of use + flexibility.

When a button is clicked, how do I show an element if another element contains a specific text?

When I click on the button, I want the #test2 element to show if span.test1 contains the keyword 'TEST'. I'm new with jquery so I'm not sure what I need to change here.
$(document).ready(function(){
$("#button").click(function()
if ($("span.test1:contains(TEST)") {
$("#test2").show()
};
};
#test2 {
display: none;
}
<input id="button" type="button" value="Button"></input>
<span class="test1">TEST</span>
<div id="test2">TEST2</div>
<!-- begin snippet: js hide: false console: true babel: false -->
You can do it as shown below. I used the is() method so that we can cache reference to the element and test :contains selector against it.
Otherwise the selectors inside click handler will be looked up on each click.
const $test1 = $("span.test1");
const $test2 = $("#test2");
$("#button").click(function() {
if ($test1.is(':contains("TEST")')) {
$test2.show()
};
});
#test2 {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="button" type="button" value="Button"></input>
<span class="test1">TEST</span>
<div id="test2">TEST2</div>
<!-- begin snippet: js hide: false console: true babel: false -->
Use RegExp to check if the string contains a specific word or not.
$("#button").click(function() {
var txt = $("span.test1").text();
if (/test/i.test(txt)) // "i" is for case case-insensitive
$("#test2").show()
});
#test2 {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="button" type="button" value="Button"></input>
<span class="test1">this is a sample TEST</span>
<div id="test2">TEST2</div>
<!-- begin snippet: js hide: false console: true babel: false -->
You can use following code
$('#button').click(function(){
if(document.getElementById("test1").innerText.includes("TEST")){
$('#test2').html("yes it includes")
console.log("yes")
}
})
<input id="button" type="button" value="Button"></input>
<span id="test1">TEST</span>
<div id="test2"></div>

How to add spaces between different tags

I have some code that looks like this
<div class="topnav">
<div>{{getGameView.Game.gameplayers[0].player.username}}</div>
<p>VS</p>
<div v-if="getGameView.Game.gameplayers.length > 1">
  {{getGameView.Game.gameplayers[1].player.username}}
 </div>
<div v-else>Waiting for opponent...</div>
</div>
Which prints this: NameVSName
I am trying to make it so that between Name and VS there is some space but cannot figure out how to do it.
A solution is to give to the VS element a class like .vs and add some padding to it:
p {
margin: 0;
}
.topnav {
display: flex;
}
.topnav .vs {
padding-right: 10px;
padding-left: 10px;
}
<div class="topnav">
<div>Name</div>
<p class="vs">VS</p>
<div>Name</div>
</div>
You can insert a space in html with .
Vue.config.devtools = false;
Vue.config.productionTip = false;
var app = new Vue({
el: '#app',
data: {
nameA: "Job",
nameB: "Bob"
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
{{ nameA }} Vs {{ nameB }}
</div>
How to insert spaces/tabs in text using HTML/CSS

Tried to apply css to a component conditionally using prop but its not working

.storyMobile{
color:green;
}
.storyWeb{
color:red;
}
<div class="storyMobile">
hii
</div>
<div class="storyWeb">
hii
</div>
//main view
<div>
<story :story="stories[0]"/>
</div>
//here it prints stories in red colour but I want it to be displayed in green colour - how can I do this?
This is my component where I have 2 divs with 2 different classes one will be active for mobile and one will be active for web.
<div class="storyMobile">
//code
</div>
<div class="storyWeb">
//code
</div>
//this is my main view where I am importing this component
<div class="body-frame">
<Header></Header>
<section class="content-section-bar" v-if="stories && stories.length">
<div>
<story :story="stories[0]"/>
</div>
</section>
</div>
By default the story component is in web so "storyweb" class is getting applied to it but I want the "storyweb" class to get applied on it.
How should I do it in vue.js I tried using the props but didn't get the desired output.
Is it what you want?
your component:
<div :class="className"></div>
script:
export default {
props: {
className: {
default: 'storyWeb'
}
}
}
usage:
<story :story="stories[0]"/>
<story :story="stories[0]" class-name="storyMobile"/>
Vue.component('story',{
template: `<div :class="className">test</div>`,
props: {
className: {
type: String,
default: 'storyWeb'
},
story: {
type: Object,
required: true
}
}
})
var app = new Vue({
el: '#app',
data () {
return {
stories: [
{content: 'sotry1 content'},
{content: 'story2 content'}
]
}
}
})
.storyMobile{
color:green;
}
.storyWeb{
color:red;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<story :story="stories[0]" class-name="storyMobile"></story>
<story :story="stories[1]"></story>
</div>

Flicker with ngMessages and ngShow

On a form with required-validation and ng-messages I use ng-show to hide the directive on startup and only show error messages after the input got ng-dirty.
To still keep the element filling it's space in the layout I have following css rule to overwrite the default ng-hide behaviour:
ng-messages.ng-hide:not(.ng-hide-animate), [ng-messages].ng-hide:not(.ng-hide-animate)
{
display: block !important;
visibility: hidden;
}
When I now enter text in the input field the error message is shortly visible before it is then hidden again (due to the required field being filled). It somehow feels like ng-dirty is resolved before the form validation is done, resulting in this behaviour.
See this Fiddle
or check out the
Code:
var $scope;
var app = angular.module('myapp', ['ngMessages', 'ngAnimate']);
app.controller('UserCtrl', ['$scope', UserCtrl]);
function UserCtrl($scope) {
$scope.showField = true;
$scope.reset = function() {
var master = { name: '' };
$scope.temp = angular.copy(master);
$scope.user_form.$setPristine();
}
}
ng-messages.ng-hide:not(.ng-hide-animate), [ng-messages].ng-hide:not(.ng-hide-animate)
{
display: block !important;
visibility: hidden;
}
ng-messages, [ng-messages]
{
display: block;
height: 1em;
}
input
{
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular-animate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-messages/1.5.5/angular-messages.min.js"></script>
<div ng-app="myapp">
<div ng-controller="UserCtrl">
<form name="user_form" novalidate>
<input name="name" ng-model="temp.name" ng-show="showField" placeholder="Name" required autocomplete="off"/>
<ng-messages ng-show="user_form.name.$dirty" for="user_form.name.$error">
<ng-message when="required">
Please enter your name
</ng-message>
</ng-messages>
<button type="button" class="button" ng-click="reset()">Reset</button>
</form>
<p>
Pristine: {{user_form.$pristine}}
</p>
<pre>Errors: {{user_form.$error | json}}</pre>
</div>
</div>
<ng-messages ng-show="user_form.name.$dirty && !user_form.name.$valid" for="user_form.name.$error">