Apply css in dynamic injected html - javascript

I am doing something like StackOverflow editor. Fetch markdown text, transfer it to HTML, and inject it into the preview area. But when I tried to apply CSS to the injected HTML elements, it was ignored. In browser inspection, I can not find the stylesheet I write for the elements. I guess this is about the order of CSS rendering. Any suggestion will be appreciated.
<template>
<div>
<div class="item">
<label for="content">Contents</label>
<textarea name="content" id="content" v-model="mdtext"></textarea>
</div>
<div id="preview"></div>
</div>
</template>
<script>
import marked from 'marked'
export default {
data () {
return {
mdtext: ''
}
},
watch: {
mdtext: function () {
document.getElementById('preview').innerHTML = marked(this.mdtext)
}
}
}
</script>
<style scoped>
...
#preview p{
width: 100%;
word-break: break-all;
word-wrap: break-word;
}
...
</style>

You're using scoped css, which makes Vue add that data-v- attribute to the p as well. However, the generated <p> doesn't not have that same data-v- attribute, which is why it's not working.
You can easily fix it by using the deep selector:
<style scoped>
#preview >>> p {
}
</style>
Reference: https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors

Related

Webcomponents is re-initializing every time while working with Vue js

I have created a webcomponent for a generic input boxes that i needed across multiple projects.
the design functionality remains same only i have to use switch themes on each projects.so i have decided to go on with webcomponents.One of the projects is based on Vue Js.In Vue js the DOM content is re-rendered while each update for enabling reactivity. That re-rendering of vue template is reinitializing my custom webcomponent which will result in loosing all my configurations i have assigned to the component using setters.
I know the below solutions. but i wanted to use a setter method.
pass data as Attributes
Event based passing of configurations.
Using Vue-directives.
using v-show instead of v-if
-- Above three solutions doesn't really match with what i am trying to create.
I have created a sample project in jsfiddle to display my issue.
Each time i an unchecking and checking the checkbox new instances of my component is creating. which causes loosing the theme i have selected. (please check he active boxes count)
For this particular example i want blue theme to be displayed. but it keep changing to red
JSFiddle direct Link
class InputBox extends HTMLElement {
constructor() {
super();
window.activeBoxes ? window.activeBoxes++ : window.activeBoxes = 1;
var shadow = this.attachShadow({
mode: 'open'
});
var template = `
<style>
.blue#iElem {
background: #00f !important;
color: #fff !important;
}
.green#iElem {
background: #0f0 !important;
color: #f00 !important;
}
#iElem {
background: #f00;
padding: 13px;
border-radius: 10px;
color: yellow;
border: 0;
outline: 0;
box-shadow: 0px 0px 14px -3px #000;
}
</style>
<input id="iElem" autocomplete="off" autocorrect="off" spellcheck="false" type="text" />
`;
shadow.innerHTML = template;
this._theme = 'red';
this.changeTheme = function(){
this.shadowRoot.querySelector('#iElem').className = '';
this.shadowRoot.querySelector('#iElem').classList.add(this._theme);
}
}
connectedCallback() {
this.changeTheme();
}
set theme(val){
this._theme = val;
this.changeTheme();
}
}
window.customElements.define('search-bar', InputBox);
<!DOCTYPE html>
<html>
<head>
<title>Wrapper Component</title>
<script src="https://unpkg.com/vue"></script>
<style>
html,
body {
font: 13px/18px sans-serif;
}
select {
min-width: 300px;
}
search-bar {
top: 100px;
position: absolute;
left: 300px;
}
input {
min-width: 20px;
padding: 25px;
top: 100px;
position: absolute;
}
</style>
</head>
<body>
<div id="el"></div>
<!-- using string template here to work around HTML <option> placement restriction -->
<script type="text/x-template" id="demo-template">
<div>
<div class='parent' contentEditable='true' v-if='visible'>
<search-bar ref='iBox'></search-bar>
</div>
<input type='checkbox' v-model='visible'>
</div>
</script>
<script type="text/x-template" id="select2-template">
<select>
<slot></slot>
</select>
</script>
<script>
var vm = new Vue({
el: "#el",
template: "#demo-template",
data: {
visible: true,
},
mounted(){
let self = this
setTimeout(()=>{
self.$refs.iBox.theme = 'blue';
} , 0)
}
});
</script>
</body>
</html>
<div class='parent' contentEditable='true' v-if='visible'>
<search-bar ref='iBox'></search-bar>
</div>
<input type='checkbox' v-model='visible'>
Vue's v-if will add/remove the whole DIV from the DOM
So <search-bar> is also added/removed on every checkbox click
If you want a state for <search-bar> you have to save it someplace outside the <search-bar> component:
JavaScript variable
localStorage
.getRootnode().host
CSS Properties I would go with this one, as they trickle into shadowDOM
...
...
Or change your checkbox code to not use v-if but hide the <div> with any CSS:
display: none
visibility: hidden
opacity: 0
move to off screen location
height: 0
...
and/or...
Managing multiple screen elements with Stylesheets
You can easily toggle styling using <style> elements:
<style id="SearchBox" onload="this.disabled=true">
... lots of CSS
... even more CSS
... and more CSS
</style>
The onload event makes sure the <style> is not applied on page load.
activate all CSS styles:
(this.shadowRoot || document).getElementById("SearchBox").disabled = false
remove all CSS styles:
(this.shadowRoot || document).getElementById("SearchBox").disabled = true
You do need CSS Properties for this to work in combo with shadowDOM Elements.
I prefer native over Frameworks. <style v-if='visible'/> will work.. by brutally removing/adding the stylesheet.

VueJS: dynamic class name inside style tags

I have a VueJS application which contains some Materializecss modals, all wrapped within single page components. Due to the nature of the application I have to assign dynamic unique IDs to each modal. Below is a snippet:
<template>
<div :id="modal_id" :class="'modal '+modal_id">
<div class="modal-content">
.... stuff here
</div>
<div class="modal-footer">
<a class="modal-close waves-effect waves-green btn-flat">Exit</a>
</div>
</div>
</template>
<style type="text/css" scoped>
.modal {
width: 90% !important;
height: 100% !important;
}
.modal_id
{
background-color: black;
}
</style>
<script type="text/javascript">
import pdf from 'vue-pdf'
export default {
data: function() {
return {
modal_id: 'ViewPdf_'+this.$root.g(), // this.$root.g() returns a unique integer
}
},
}
</script>
My question is if it's possible to use Vue to modify the custom class name from within <style></style> tags to match the class name generated when component is mounted. If not, what workarounds I could use?
<style type="text/css" scoped>
.modal {
width: 90% !important;
height: 100% !important;
}
.modal_id // <--- I wish this class name was the same with value of this.modal_id
{
background-color: black;
}
</style>
If the CSS is all contained in your Vue component, you could just produce the style information in your component rather than trying to match up the css selector based on the DOM id.
Specifically, instead of doing this:
<div :id="modal_id" :class="'modal '+modal_id">
Do this:
<div :id="modal_id" :style="modalStyle">
and then within your component, have a computed property for the style, using the guidelines at https://v2.vuejs.org/v2/guide/class-and-style.html#Binding-Inline-Styles
For example:
computed: {
modalStyle: function () {
return {backgroundColor: 'black'};
}
}
You can build a computed property that will react to changes in modal_id and calculate a class name that you want to attach to particular modal.
<template>
<div :id="modal_id" :class="className">
...
</div>
</template>
<script type="text/javascript">
export default {
data: function() {
return {
}
},
computed: {
className: function () {
if (this.modal_id === <your modal_id1>) return 'class1';
else if (this.modal_id === <your modal_id2>) return 'class2';
},
modal_id: function () {
return 'ViewPdf_'+this.$root.g()
}
}
}
</script>
<style>
.class1{}
.class2{}
</style>
the modal_id also should be a computed property if you want to make it dynamic.
Yes, you can edit the css property name with javascript if you use an external css file. Here is a simple example in pure javascript that shows how I change the name of the css name, thereby placing its style on the second paragraph.
//the index of the stylesheet based on load order
var cssIndex = 0;
var cssRules = (document.all) ? 'rules' : 'cssRules';
function changeClass() {
for (i = 0, len = document.styleSheets[cssIndex][cssRules].length; i < len; i++) {
if (document.styleSheets[cssIndex][cssRules][i].selectorText === ".text") {
document.styleSheets[cssIndex][cssRules][i].selectorText = ".text2";
return;
}
}
}
.text {
text-align: center;
}
<button onclick='changeClass()'> Change css property class name </button>
<p id="1" class="text">This is text class</p>
<p id="2" class="text2"> This is text2 class</p>
I hope you can apply it in your Vue code.

How to target a component in svelte with css?

How would I do something like this:
<style>
Nested {
color: blue;
}
</style>
<Nested />
i.e. How do I apply a style to a component from its parent?
You need to pass props to the parent component with export let, then tie those props to class or style in the child component.
You can either put a style tag on the element in the child you want to style dynamically and use a variable you export for the parent to determine the value of a style directly, then assign the color on the tag like this:
<!-- in parent component -->
<script>
import Nested from './Nested.svelte';
</script>
<Nested color="green"/>
<!-- in Nested.svelte -->
<script>
export let color;
</script>
<p style="color: {color}">
Yes this will work
</p>
Upside here is flexibility if you only have one or two styles to adjust, downside is that you won't be able to adjust multiple CSS properties from a single prop.
or
You can still use the :global selector but just add a specific ref to the element being styled in the child like so:
<!-- in parent component -->
<script>
import Nested from './Nested.svelte';
</script>
<Nested ref="green"/>
<style>
:global([ref=green]) {
background: green;
color: white;
padding: 5px;
border-radius: .5rem;
}
</style>
<!-- in Nested.svelte -->
<script>
export let ref;
</script>
<p {ref}>
Yes this will work also
</p>
This ensures global only affects the exact ref element inside the child it's intended for and not any other classes or native elements. You can see it in action at this REPL link
The only way I can think of is with an additional div element.
App.svelte
<script>
import Nested from './Nested.svelte'
</script>
<style>
div :global(.style-in-parent) {
color: green;
}
</style>
<div>
<Nested />
</div>
Nested.svelte
<div class="style-in-parent">
Colored based on parent style
</div>
Multiple Nested elements
You could even allow the class name to be dynamic and allow for different colors if you use multiple Nested components. Here's a link to a working example.
You could use inline styles and $$props...
<!-- in parent component -->
<script>
import Nested from './Nested.svelte';
</script>
<Nested style="background: green; color: white; padding: 10px; text-align: center; font-weight: bold" />
<!-- in Nested.svelte -->
<script>
let stylish=$$props.style
</script>
<div style={stylish}>
Hello World
</div>
REPL
using :global(*) is the simplest solution.
No need to specify a class in the child if you want to style all immediate children for example
In the parent component:
<style>
div > :global(*) {
color: blue;
}
<style>
<div>
<Nested />
<div>
Nested will be blue.
I take a look and found nothing relevant (maybe here), so here is an alternative by adding <div> around your custom component.
<style>
.Nested {
color: blue;
}
</style>
<div class="Nested">
<Nested />
</div>
Maybe you will found something but this one works.
The way I do it is like this:
<style lang="stylus">
section
// section styles
:global(img)
// image styles
</style>
This generates css selectors like section.svelte-15ht3eh img that only affects the children img tag of the section tag.
No classes or tricks involved there.

How to restrict the scope of dynamic HTML CSS in Angular 4 [duplicate]

I would like to apply a CSS file to a concrete DIV in my page. This is the page structure:
<link rel="stylesheet" href="style.css" />
...
<body>
<div id="pagina-page" data-role="page">
...
<div id="applyCSS">
(all the elements here must follow a concrete CSS rules)
</div>
...
</body>
I tried to apply the rules of the CSS file editing it like this (the CSS file is so large):
#applyCSS * { (For all the elements inside "applyCSS" DIV:)
.ui-bar-a {
...
...
}
.ui-bar-a .ui-link-inherit {
...
}
...
}
But that solution doesn't work. So, how can I do that?
#applyCSS > * {
/* Your style */
}
Check this JSfiddle
It will style all children and grandchildren, but will exclude loosely flying text in the div itself and only target wrapped (by tags) content.
You could try:
#applyCSS .ui-bar-a {property:value}
#applyCSS .ui-bar-a .ui-link-inherit {property:value}
Etc, etc... Is that what you're looking for?
.yourWrapperClass * {
/* your styles for ALL */
}
This code will apply styles all elements inside .yourWrapperClass.
I do not understand why it does not work for you, it works for me : http://jsfiddle.net/igorlaszlo/wcm1soma/1/
The HTML
<div id="pagina-page" data-role="page">
<div id="applyCSS">
<!--all the elements here must follow a concrete CSS rules-->
<a class="ui-bar-a">This "a" element text should be red
<span class="ui-link-inherit">This span text in "a" element should be red too</span>
</a>
</div>
</div>
The CSS
#applyCSS * {color:red;display:block;margin:20px;}
Maybe you have some special rules that you did not share with us...
If you're looking for a shortcut for writing out all of your selectors, then a CSS Preprocessor (Sass, LESS, Stylus, etc.) can do what you're looking for. However, the generated styles must be valid CSS.
Sass:
#applyCSS {
.ui-bar-a {
color: blue;
}
.ui-bar-a .ui-link-inherit {
color: orange;
}
background: #CCC;
}
Generated CSS:
#applyCSS {
background: #CCC;
}
#applyCSS .ui-bar-a {
color: blue;
}
#applyCSS .ui-bar-a .ui-link-inherit {
color: orange;
}
Write all class/id CSS as below. #applyCSS ID will be parent of all CSS code.
For example you add class .ui-bar-a in CSS for applying to your div:
#applyCSS .ui-bar-a { font-size:11px; } /* This will be your CSS part */
Below is your HTML part:
<div id="applyCSS">
<div class="ui-bar-a">testing</div>
</div>
Alternate solution. Include your external CSS in your HTML file by
<link rel="stylesheet" href="css/applyCSS.css"/>
inside the applyCSS.css:
#applyCSS {
/** Your Style**/
}

Vue.js conditional module styles

I want to separate the styles in a Vue.js component in modules.
Each style module will have far more than just a class, and new classes will be added regularly. So, it will be hard to change the entire component's template. So, I'm looking for a more practical solution.
I came with the idea of, using a v-if in the styles, but not exactly sure how it should be implemented or if such thing is possible after all.
It will be way more practical, if just depending on the name sent with props, the entire styles changes.
<template>
<div class="color-text">
Text in the color of the class with just the name
</div>
</template>
<script>
export default {
name: 'comp',
props: ['name']
}
</script>
<!-- General styles -->
<style scoped>
div{
float: right;
}
</style>
<!-- red styles -->
<style module v-if="name === 'red'">
.color-text{
color: red;
}
</style>
<!-- blue styles -->
<style module v-if="name === 'blue'">
.color-text{
color: blue;
}
</style>
<!-- green styles -->
<style module v-if="name === 'green'">
.color-text{
color: green;
}
</style>
If I was tackling this I'd use a transitive class value. and not worry about props at all.
<template>
<div class="color-text">
Text in the color of the class with just the name
</div>
</template>
<script>
export default {
name: 'comp'
}
</script>
<!-- General styles -->
<style scoped>
div{
float: right;
}
.red .color-text{
color: red;
}
.blue .color-text{
color: blue;
}
.green .color-text{
color: green;
}
</style>
then you can use the class property to pass in your color type
<div id="app">
<comp class="red"></comp>
<comp class="green"></comp>
<comp class="blue"></comp>
</div>
I've put together an example jsfiddle though it may need some tweaking when it comes to scoped styles and how webpack handles the injection

Categories