I want a button to toggle between two views on click. The code is:
<template>
<button #click="switchSheet">{{ currentSheet }}</button>
<component :is="sheetView" :key="componentKey" />
</template>
<script setup>
import DisplaySheetClassrooms from "./components/ds-classrooms.vue";
import DisplaySheetChromebooks from "./components/ds-chromebooks.vue";
let sheetView = DisplaySheetClassrooms;
let currentSheet = ref("HS Classrooms");
const switchSheet = () => {
if (sheetView == DisplaySheetClassrooms) {
sheetView = DisplaySheetChromebooks;
currentSheet.value = "HS Chromebooks";
} else {
sheetView = DisplaySheetClassrooms;
currentSheet.value = "HS Classrooms";
}
};
Documentation states
":is can contain either:
the name string of a registered component, OR
the actual imported component object"
I am using the actual imported component but looking at Devtools switchView never changes value on click. I also tried it with string quotes and still no good. I tried solution here but it did not work for me. Could somebody clarify how to get this working . Thanks in advance.
This seems to work for me:
Use a components object and have the component name key (sheetView in your case) used to target the key in the component :is value
example:
<template>
<button #click="switchSheet">{{ currentSheet }}</button>
<component :is="components[currentSheet]" :key="currentSheet" />
</template>
<script setup>
import DisplaySheetClassrooms from "./components/ds-classrooms.vue";
import DisplaySheetChromebooks from "./components/ds-chromebooks.vue";
let currentSheet = ref("DisplaySheetChromebooks");
// create an object key (doesn't need to be a ref)
const components = {
DisplaySheetChromebooks,
DisplaySheetClassrooms,
}
const switchSheet = () => {
if (currentSheet === "DisplaySheetClassrooms) {
currentSheet = "DisplaySheetChromebooks";
} else {
currentSheet = "DisplaySheetClassrooms";
}
};
</script>
Related
So, I'm trying to create a React App that changes the background image of the body. I did this by giving the body in my index.html an id of "body." I can get this to work with changing the background COLOR just fine. When I try to reassign the background IMAGE, though, I can't seem to get it to work no matter what I try.
This works:
document.getElementById("body").style.backgroundColor = "blue";
This doesn't:
import explosion from "./explosion.png";
function Boom(){
document.getElementById("body").style.backgroundImage = "url('" + {explosion} +
"')";
Why? I've tried writing this many different ways.
this worked for me :
import { useEffect } from "react";
import img from './img.png';
export default function App(){
useEffect(()=>{
document.getElementById('body').style.backgroundImage = `url('${img}')`;
})
return <>
<div id="body"
style={{height:'300px'}}
>
</div>
</>
}
or you can use inline css style :
import img from './img.png';
export default function App(){
return <>
<div id="body"
style={{
height:'300px',
backgroundImage: `url('${img}')`,
}}
>
</div>
</>
}
you need to pass the URL of the image as a string, without wrapping it in curly braces {}
You can try this code
import { useEffect } from "react";
export default function App() {
const bgUrl =
"https://images.unsplash.com/photo-1605106250963-ffda6d2a4b32?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=880&q=80";
/*useEffect Hook allows you to perform side effects in your components. Such as fetching data, directly updating the DOM, and timers*/
useEffect(() => {
Boom();
}, []);
const Boom = () => {
document.getElementById("body").style.backgroundImage = `url(${bgUrl})`;
};
return (
<div className="App">
<h1>Hello World!</h1>
</div>
);
}
here's a link to the working demo Change Background Image
The code below should display my prop default value ("test") since it received no other value. Yet it displays nothing. Why not?
<template>
<div>
{{ propValue }}
</div>
</template>
<script setup lang="ts">
import { defineProps } from "vue"
const props = defineProps<{
myProp: {
type: string
default: "test"
}
}>()
const propValue = props.myProp
</script>
There are two reasons why.
When you use props with TypeScript you lose the ability to set default values, but it can be fixed using the withDefaults macro (you also need to separately declare a Props interface). Side note: I would not use the alternative experimental "Reactivity Transform" solution noted in the docs (it's being removed soon)
export interface Props {
myProp?: string;
}
const props = withDefaults(defineProps<Props>(), {
myProp: 'test'
});
This one isn't actually strictly necessary, but props is a reactive object, and when you assign a single property of props to a new variable, the reactivity breaks. In order to maintain reactivity and stay synced with any future changes to props, use the toRef function
const propValue = toRef(props, 'myProp');
and be sure to import it: import { defineProps, toRef } from 'vue';
How can I get the current route using useRoute for a component that's outside of the <router-view />? Is this possible?
Breadcrumbs.vue
<script setup>
import {useRoute} from 'vue-router'
const route = useRoute()
console.log(route.name) // undefined
</script>
App.vue
<template>
<Breadcrumbs />
<router-view />
</template>
The alternative is that I have to put <Breadcrumbs /> at the top of every single view component, and I was hoping to avoid that and instead just include it once in my App.vue
route.name is undefined in your example because that's the initial value when the component is rendered before the route has resolved.
For the component to reactively update based on the current route, use a watcher (e.g., watch or watchEffect):
import { watchEffect } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
watchEffect(() => {
console.log(route.name)
})
demo
In your main file, try to mount app like this
router.isReady().then(() => {
app.mount('#app');
});
then useRoute() should be ready in your component
I have a form that once certain checkboxes are checked, I need them to v-show additional form components. I can get it to work, sort of. If you only choose 1 option, it will populate the correct form, however, If multiple choices are made it doesn't show the additional forms components. Here is my code. It seems that am getting the correct values through the store, I'm just missing something. I apologize in advance if this is a duplicate question. I feel like I've read all of stackoverflow in the last few weeks :) Here is a screencast of it somewhat working http://somup.com/c3hD0TtnJh
I'm using Formkit, Vue3, Pinia. Thanks in advance.
App.vue
<template>
<ReasonForVisit />
<Sports v-show="data.reasonForVisit == 'si' " />
<WorkComp v-show="data.reasonForVisit == 'wc' " />
<Accident v-show="data.reasonForVisit == 'aa' " />
</template>
<script>
import ReasonForVisit from './components/ReasonForVisit.vue'
import Sports from './components/Sports.vue'
import WorkComp from './components/WorkComp.vue'
import Accident from './components/Accident.vue'
import { useFormStore} from './stores/formStore.js'
const data = useFormStore()
</script>
ReasonForVisit.vue
<template>
<FormKit
v-model="data.reasonForVisit"
type="checkbox"
label="Reason for Visit"
:options="{
we: 'Wellness Check',
aa: 'Auto Accident',
si: 'Sports Injury',
wc: 'Work Comp' }"
validation="required"
#change="data.checkedReason"
/>
<p>reason: {{ data.reasonForVisit }}</p>
</template>
FormStore.js
import { defineStore } from 'pinia'
import { differenceInYears, parseISO } from 'date-fns'
export const useFormStore = defineStore('formStore', {
state: () => ({
reasonForVisit: [],
}),
},
}
)
Your reasonForVisit is an array as you initialize it in FormStore.js as reasonForVisit: [].
Instead of data.reasonForVisit == 'si' and others, if you check for data.reasonForVisit.includes('si'), it should work as intended.
It shouldn't be working for 1 option too right now, I think the only reason it works for the 1 option case is the == operator considers si to be the same as ['si']. You should use strict equality to avoid such bugs in js.
You cannot compare Array with string. You need to iterate it or filter or use include method on it and check are it contains correct word. To do that, read about computed() properties. And if you are new to programming, use === not just == or you end up with bad errors in code.
Example:
<template>
<ReasonForVisit />
<Sports v-show="containsSi" />
<WorkComp v-show="containsWc" />
<Accident v-show="containsAa" />
</template>
<script>
import ReasonForVisit from './components/ReasonForVisit.vue'
import Sports from './components/Sports.vue'
import WorkComp from './components/WorkComp.vue'
import Accident from './components/Accident.vue'
import { useFormStore} from './stores/formStore.js'
const data = useFormStore()
const containsSi = computed(() => data.reasonForVisit.includes('si'))
const containsWc = computed(() => data.reasonForVisit.includes('wc'))
const containsAa = computed(() => data.reasonForVisit.includes('aa'))
</script>
So what's the best pratice for using className in react. In specific multiple class names. I'm reading through the documentation and I don't really get a clear answer. I've seen things like:
const divStyle = {
color: 'blue',
backgroundImage: 'url(' + imgUrl + ')',
};
function HelloWorldComponent() {
return <div style={divStyle}>Hello World!</div>;
}
but is there a way for me to do something like this?
import React from 'react';
import ReactDOM from 'react-dom';
import './css/landing.css';
import './css/w3.css';
class Home extends React.Component {
const homeClasses = 'bgimg-1 w3-display-container w3-opacity-min';
render() {
return (
<div className={homeClasses}>
<h1>SUP</h1>
</div>
);
}
}
ReactDOM.render(
<Home />,
document.getElementById('root')
);
or even just list then out in the class name section?
It depends what your component should/will do.
If your component is fairly static you will want to use a built in style like your first example:
const mystyle = {
width: '100%',
...
}
<div style={mystyle}>...</div>
However, there are better ways that allow your component to be more dynamic for re-use, for instance using a class method to generate the style from props passed to it, like in this render function:
render() {
// User's preference or Default Style:
const defaultStyle = {
width: this.props.style.width || '100%',
height: this.props.style.height || '100%',
}
//if this.props.className doesn't exist use mycssclass
const defaultClassName = this.props.className || 'mycssclass'
return (
<div className={defaultClassName} style={defaultStyle}>...</div> )
Following this logic you can use the ternary operator to change the css class name based on props. A common solution is use an isActive state property and use it to determine which class should be used.
render() {
const activeClassName = this.props.className + ' mycomponent-active'
return (
<div className={this.props.isActive ? activeClassName : this.props.className} style={ this.props.style }
</div>);
}
Another common, but complex way to set your component's style is to use a function that will return a given style object, and use it like the first example.
Ultimately, you should decided whether you would like your component to be styled by the designer/user or should look the same no matter where it is used... if it is styled by the designer, just expose the CSS class name from props to the component or define a default:
<div className={this.props.className || 'someclassName'}>...</div>
otherwise, use an example above.
Yes, you can do this! Take a look at the snippet below:
class Example extends React.Component {
cssClasses = 'demo demo2';
render() {
return (
<div className = { this.cssClasses }>
Hello World
</div>
);
}
}
ReactDOM.render( <Example/> , document.getElementById('app'));
.demo {
color: blue
}
.demo2 {
font-size: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app'></div>
Your error was the definition of the homeClasses. You can't declare it like
const homeClasses = '...';
Because, on the way that you did, homeClasses is a property of your component. You should not use const. Just:
homeClasses = '...';
And you forgot to use the this reference, because the homeClasses is an attribute of your component.
<div className={this.homeClasses}>
<h1>SUP</h1>
</div>
Exists and one away for this problem. You can use and read this data from file (example data.json) where can use this data like props of that.