Vuetife overwrite components scoped styles - vue.js

I create an application using Vuetify. One component should display a schedule that is created using dxhtmlScheduler. But global Vuetify styles overwrite local dxhtmlScheduler styles and therefore the schedule is not displayed correctly. How to make dxhtmlScheduler styles a particular component had a higher priority than the styles Vuetify?
<template >
<div id="scheduler_here" class="dhx_cal_container" style='width:100%; height:100%;'>
<div class="dhx_cal_navline">
<div class="dhx_cal_prev_button"> </div>
<div class="dhx_cal_next_button"> </div>
<div class="dhx_cal_today_button"></div>
<div class="dhx_cal_date"></div>
<div class="dhx_cal_tab" name="day_tab"></div>
<div class="dhx_cal_tab" name="week_tab"></div>
<div class="dhx_cal_tab" name="month_tab"></div>
</div>
<div class="dhx_cal_header"></div>
<div class="dhx_cal_data"></div>
</template>
<script>
import 'dhtmlx-scheduler'
export default {
name: "Scheduler",
mounted() {
scheduler.init("scheduler_here");
}
}
</script>
<style scoped>
#import "../../node_modules/dhtmlx-scheduler/codebase/dhtmlxscheduler_material.css";
</style>

The markup generated by dhtmlxScheduler lives outside vue component scope, so I don't think scoped styles would work with it.
Try removing scoped attribute from your style declaration
<style>
#import "../../node_modules/dhtmlx-scheduler/codebase/dhtmlxscheduler_material.css";
</style>
Here is a related github issue https://github.com/vuejs/vue-loader/issues/559
Explanation:
Vue adds a special data-v-xxxxxxx attribute to html elements created by your component.
Vue css-loader in its turn modifies selectors in scoped css in order to explicitly match elements inside your component and nothing outside.
So .dhx_cal_event_line { background: blue; } in dhtmlscheduler.css becomes .dhx_cal_event_line[data-v-xxxxxxx] { backtround: blue; } when loaded to the page. Such style is supposed to only affect a component with the matching value of data-v attribute.
The problem is, DOM elements of dhtmlxscheduler are created by the library code outside the vue component knowledge, they don't have vue data-v-xxxxxxx attributes, thus scoped css selectors no longer matches them.
Thus, you'll have to load scheduler css as a global style.
There is maybe a better solution, but unfortunately, I don't know it.

Related

How do I add a class to a slotted element?

In my my-dropdown component in Stencil, I have this:
<slot name="filter" />
In my HTML, I have this:
<my-dropdown label="dropdown" size="m" filter="true">
<select slot="filter" class="inf__dropdown-select">
<option>One</option>
<option>Two</option>
<option>Three</option>
</select>
</my-dropdown>
The class inf__dropdown-select is defined in the stylesheet of the component, and it used to be applied to the select element inside the component.tsx, but since I need to slot it now, I replaced the select element with a single <slot name="filter" /> slot, but now I don't know how do I apply the class? If I add the class to the slot inside the component, it's not being
applied. I thought adding it to the element that you are slotting would work, but it doesn't. How do I make sure the class is applied to the slotted select element?
You have implemented the inf__dropdown-select style class inside shadow DOM (the style for my-dropdown), but the class is being set on the select element which is in light DOM, so the style can never be applied to the element.
To style elements inside a slot of a web component from inside the component, you use the ::slotted() pseudo-element selector inside the component's stylesheet.
For example - the stylesheet for my-dropdown:
:host {
::slotted(select) {
...
}
...
}
You can also use other selectors inside the ::slotted() function such as ::slotted(.inf__dropdown-select), ::slotted(select.inf__dropdown-select) or ::slotted([slot="filter"]) depending on how specific you need to be according to the design of your component.
Important to note: Slotted content is reflected, NOT moved!
<slot> content is styled by CSS in the container
in the SO snippet below global CSS myClass
Below <style> can be inside the component (in lightDOM !!) or outside the component.
and inside the component,
the "skin" (only the first! element select) can be styled with ::slotted
For really deep dive, see: ::slotted CSS selector for nested children in shadowDOM slot
customElements.define("my-dropdown",class extends HTMLElement{
constructor(){
super()
.attachShadow({mode:"open"})
.innerHTML = `
<style>
::slotted(select) {
margin:3em;
}
div {
background:pink;
}
</style>
<div>
<slot name="filter">NO slot named: filter</slot>
</div>
`
}
})
<style>
select {
font:20px arial;
}
</style>
<my-dropdown label="dropdown" size="m" filter="true">
<style>
.myClass {
border: 5px dashed green;
}
</style>
<select slot="filter" class="myClass">
<option>One</option>
<option>Two</option>
<option>Three</option>
</select>
</my-dropdown>

Require is not a function in vue-cli project while rendering using template attribute

I'm new to Vue js (I'm using vue3) and I've detected a bit weird behavior at my Component while image rendering
I have a project with 2 endpoints Home.vue and InitializationModal.vue
The Problem is, that while rendering the InitializationModal.vue component, the vue does not determine the require as a function for some reason (I put the template into the template attribute of the component, not into the separated tag)
I have the same template at Home.vue (but it is in separated template tag), however it works perfect.
What's wrong with it?
To better explain the problem, there is some snippets provided down below
I've cut it as much as it possible to make it easier to understand
Snippet of the Home.vue (that is in separated tag)
<template>
<div v-else class="empty flex flex-column">
<img :src="require('#/assets/illustration-empty.svg')" style="width: 50%; height: 50%; margin" alt="illustration-empty" />
<h3>There is nothing here</h3>
<p>Let's create a new Virtual Server Now!</p>
</div>
</div>
</template>
<script>
...// my component goes there
</script>
InitializationModal.vue
<script>
export default {
name: "hardwareConfiguration",
template: `
<div class="hardwareConfiguration flex flex-column">
<h4>Hardware Configuration</h4>
<v-select :options="Datacenters" #input="validateDatacenter" label="title">
<template slot="Datacenter" slot-scope="Datacenter">
<img :src="require('#/assets/some_image.svg')" style="height: 20%; width: 20%" />
{{ Datacenter.DatacenterName }}
</template>
</v-select>
`,
};
</script>
the Error that is being returned at the InitializationModal.vue : Uncaught (in promise) TypeError: require is not a function
Using require( like this is not really Vue, it's Webpack which reads your require method, transforms the path to an absolute path which the browser understands (or possibly a base64 encoded string, depending on url-loader settings). The problem is webpack will only transform Javascript, not the full string of your template property. Maybe try like this:
`<img :src="${require('#/assets/some_image.svg')}" style="height: 20%; width: 20%" />`
or just use regular SFC template syntax.

Vue scoped styling not working with elements that have been added inside a slot

Moving my styling to a locale setup but seeing that when I insert element into slot containers they will not work. I guess this is normal if so is there a way to solve this, keep in mind NO I am not going to place the parent (.child) styling in the parent component and NO I want to keep my CSS in seperate scss files.
component (parent)
<template>
<wrapper>
<div class="child">Hello</div>
</wrapper>
</template>
component (wrapper called)
<template>
<div class="wrapper">
<slot></slot>
</div>
</template>
<style lang="scss" scoped>
#import "../../../sass/components/_container.scss";
</style>
container.scss
.wrapper{
background-color:#333;
.child{
background-color:#fff;// not doing anything
}
}
You can use the v-deep combinator to target child elements/components e.g.:
.wrapper::v-deep .child { background-color:#fff; }
See the Deep Selectors documentation for more detail.
Update
It seems ::v-deep .child has been deprecated. Use ::v-deep(.child) {} or :deep(.child) {} instead. See the RFC for more detail.

How to tell if an html tag in vue is a custom tag or not?

I'm new to Vue and I'm looking at an existing code that makes me question, where do the tags <u-col> and <u-row> come from?
My very little understanding of Vue so far is that you can create custom components and then use those components like html tags in the template. But my understanding is that if the component is to be used then it must be exported from where it is created and then imported at where it is being used.
Below is a part of the code that I'm not sure if <u-col> or <u-row> are custom made tags or if they're simply default vue tags? I don't think they're custom tags because I don't see any imports and I haven't found anything in the source code that tells me they are custom tags. But I don't think they are default vue tags either because I haven't seen them from my google searches. The closest I've come to is the <b-col> tag but I know that is from bootstrap.
<template>
<u-row class="mb-4 flex-nowrap">
<u-col class="text-sm text-700 text-right col-2 mr-4">
<span v-if="required" class="text-warning">*</span>{{label}}
</u-col>
<u-col>
<slot />
</u-col>
</u-row>
</template>
<script>
export default {
props: {
label: {
type: String
}
}
</script>
<style>
</style>
Any help is appreciated.

v-if on a component template tag

From the docs:
Because v-if is a directive, it has to be attached to a single
element. But what if we want to toggle more than one element? In this
case we can use v-if on a element, which serves as an
invisible wrapper. The final rendered result will not include the
element.
But on my template in my component:
<template v-if="false">
<div>
....
</div>
</template>
But the component still renders.
I ask because I want a hook on the component so if v-if is true, I can do some code in beforeMounted and beforeDestroyed if false.
If I undestood what are you doing...
You're putting v-if int the template tag ina .vue file right?
Like this
// component.vue
<template v-if="false">
<div>
My Component
</div>
</template>
<script>
export default {
name: 'my-component'
};
</script>
<styles>
</styles>
Right?
If YES, you are doing it wrong.
The template there is a tag for Webpack Vue Loader to load the component template.
So the if must go inside the template tag.
// component.vue
<template>
<div v-if="false">
My Component
</div>
</template>
<script>
export default {
name: 'my-component'
};
</script>
<styles>
</styles>
If you need to "hide" multiple elements, just encapsulate into another div.
As Lucas Katayama said, you cannot use v-if inside SFC, but another way to hide you component is use v-if on this component in its parent component.
Your reference to the docs is correct, you can use a v-if on a template tag. However, I believe conditionals on the top-level <template> in a Single File Component are ignored.
To achieve the effect showed in the docs (conditional render a template) that template needs to be within the top-level template section.
Example:
<script>
// your script section
</script>
<template>
<template v-if="false">
<div>
....
</div>
</template>
</template>
<style>
// your style section
</style>