Can I use my existing vue component as a single file component - javascript

So I had a vue app that I just wrote into a .html file being served by django. I now am trying to move over to a dedicated vue.js project with the CLI and so I'm wanting to break apart all the components I had in that single file and move them into their own vue files.
My question is can I just create a file called Overview.vue and copy and paste my component into there as is? - or do I need to make some modifications?
Most examples I see of single file components have dedicated blocks for <style> <template> <script>. In my component I pasted below, the template is inside the component. Do I need to change this?
Vue.component('overview', {
delimiters: [ '[[', ']]' ],
props: ['jobs', 'links'],
template: `
<div overview>
<h3>Overview</h3>
<table :style="overviewStyle">
<tr>
<td>Start Time</td>
<td>[[ jobs[0].time_start ]]</td>
</tr>
</table>
</div>
`,
computed: {
overviewStyle() {
return {
'padding': '8px',
'width': '100%',
'display': 'table',
};
},
methods: {
getStyle (name) {
switch (name) {
case 'SUCCESS':
return {
'background-color': '#dff0d8',
'padding': '10px',
'line-height': '1.42857143',
'border': '1px solid #C0C0C0',
}
case 'IN_PROGRESS':
return {
'background-color': '#f4dc42',
'padding': '10px',
}
case 'FAILURE':
return {
'background-color': '#f45942',
'padding': '10px',
'line-height': '1.42857143',
'border': '1px solid #C0C0C0',
}
};
},
},
});

Yes, you will need to follow the structure for Vue Single File Components.
It accepts 3 blocks, <template>, <script> and <style>.
<template>
<!-- your template here -->
</template>
<script>
// javascript here
export default {
data() {
return { ... }
},
methods: { ... }
// etc
}
</script>
<style>
/* any css here */
</style>

Related

Material UI Button - How can I use "::first-letter" pseudo element selector with MuiButton class?

I am trying to have sentence case with Button text inside Material UI Button.
https://mui.com/components/buttons/
text inside the button - ADD FRIEND should become to sentence case as Add friend.
I have tried to override the theme. But it does not target the element this way.
Please suggest if this is possible to do.
createTheme({
components: {
MuiButton: {
styleOverrides: {
root: {
'&::first-letter': {
textTransform: 'uppercase',
},
},
}
}
}
});
They way I do it, is write the following code in makeStyles of the page/component:
parentOfButton: {
'& .MuiButton-root': {
textTransform: 'none',
},
},
<Box className={classes.parentOfButton}>
<Button>Text</Button>
</Box>
UPDATE
I have tried doing the same thing in createTheme, and it worked, here is the way I did it:
components: {
MuiButton: {
styleOverrides: {
root: {
textTransform: 'none',
},
},
},
},
Through styles, I could not make the first letter of the transmitted text capitalized until I wrapped the transmitted text in some kind of tag, for example
.button {
& > *::first-letter {
text-transform: uppercase;
}
}
<Button className={s.button}>
<p>some text</p>
</Button>

In React SharePoint WebPart what are the differences between using 'html-react-parser' & using 'dompurify eslint-plugin-risxss' to securely show HTML

I am trying to build a React.js SharePoint modern web part, which have the following capabilities:-
Inside the Web Part settings page >> there are 2 fields named as "Who We Are" & "Our Value" which allow the user to enter HTML.
The web part will render 2 buttons "Who We Are" & "Our Value" >> and when the user clicks on any button >> a Popup will be shown with the entered HTML code in step-1
Something as follow:-
But to be able to render HTML code as Rich-Text inside my Web Part, i have to use the dangerouslySetInnerHTML attribute inside the .tsx file. as follow:-
import * as React from 'react';
import { useId, useBoolean } from '#fluentui/react-hooks';
import {
getTheme,
mergeStyleSets,
FontWeights,
Modal,
IIconProps,
IStackProps,
} from '#fluentui/react';
import { IconButton, IButtonStyles } from '#fluentui/react/lib/Button';
export const MYModal2 = (myprops) => {
const [isModalOpen, { setTrue: showModal, setFalse: hideModal }] = useBoolean(false);
const [isPopup, setisPopup] = React.useState(true);
const titleId = useId('title');
React.useEffect(() => {
showModal();
}, [isPopup]);
function ExitHandler() {
hideModal();
setisPopup(current => !current)
myprops.handler();
}
return (
<div>
<Modal
titleAriaId={titleId}
isOpen={isModalOpen}
onDismiss={ExitHandler}
isBlocking={true}
containerClassName={contentStyles.container}
>
<div className={contentStyles.header}>
<span id={titleId}>Modal Popup</span>
<IconButton
styles={iconButtonStyles}
iconProps={cancelIcon}
ariaLabel="Close popup modal"
onClick={ExitHandler}
/>
</div>
<div className={contentStyles.body}>
<p dangerouslySetInnerHTML={{__html:myprops.OurValue}}>
</p>
</div>
</Modal>
</div>
);
};
const cancelIcon: IIconProps = { iconName: 'Cancel' };
const theme = getTheme();
const contentStyles = mergeStyleSets({
container: {
display: 'flex',
flexFlow: 'column nowrap',
alignItems: 'stretch',
},
header: [
// eslint-disable-next-line deprecation/deprecation
theme.fonts.xLarge,
{
flex: '1 1 auto',
borderTop: '4px solid ${theme.palette.themePrimary}',
color: theme.palette.neutralPrimary,
display: 'flex',
alignItems: 'center',
fontWeight: FontWeights.semibold,
padding: '12px 12px 14px 24px',
},
],
body: {
flex: '4 4 auto',
padding: '0 24px 24px 24px',
overflowY: 'hidden',
selectors: {
p: { margin: '14px 0' },
'p:first-child': { marginTop: 0 },
'p:last-child': { marginBottom: 0 },
},
},
});
const stackProps: Partial<IStackProps> = {
horizontal: true,
tokens: { childrenGap: 40 },
styles: { root: { marginBottom: 20 } },
};
const iconButtonStyles: Partial<IButtonStyles> = {
root: {
color: theme.palette.neutralPrimary,
marginLeft: 'auto',
marginTop: '4px',
marginRight: '2px',
},
rootHovered: {
color: theme.palette.neutralDark,
},
};
And to secure the dangerouslySetInnerHTML, i did the following steps:-
1- Inside my Node.Js CMD >> i run this command inside my project directory:-
npm install dompurify eslint-plugin-risxss
2- Then inside my above .tsx i made the following modifications:-
I added this import import { sanitize } from 'dompurify';
An I replaced this unsafe code <p dangerouslySetInnerHTML={{__html:myprops.OurValue}}></p> with this <div dangerouslySetInnerHTML={{ __html: sanitize(myprops.OurValue) }} />
So I have the following question:-
Now my approach (of using sanitize(myprops.OurValue) will/should securely render HTML as Rich-Text inside the popup since i am using the sanitize function which is part of the dompurify eslint-plugin-risxss. but i read another approach which mentioned that to securely render HTML as Rich-Text inside the popup, we can use the html-react-parser package as follow {parse(myprops.OurValue)}. So what are the differences between using 'html-react-parser' & using 'dompurify eslint-plugin-risxss' to securely render an HTML code as Rich-Text inside the React web part's popup?
Here is my Full web part code:-
inside the MyModalPopupWebPart.ts:-
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '#microsoft/sp-core-library';
import {
IPropertyPaneConfiguration,
PropertyPaneTextField
} from '#microsoft/sp-property-pane';
import { BaseClientSideWebPart } from '#microsoft/sp-webpart-base';
import * as strings from 'MyModalPopupWebPartStrings';
import MyModalPopup from './components/MyModalPopup';
import { IMyModalPopupProps } from './components/IMyModalPopupProps';
export interface IMyModalPopupWebPartProps {
description: string;
WhoWeAre: string;
OurValue:string;
}
export default class MyModalPopupWebPart extends BaseClientSideWebPart<IMyModalPopupWebPartProps> {
public render(): void {
const element: React.ReactElement<IMyModalPopupProps> = React.createElement(
MyModalPopup,
{
description: this.properties.description,
WhoWeAre: this.properties.WhoWeAre,
OurValue: this.properties.OurValue
}
);
ReactDom.render(element, this.domElement);
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('WhoWeAre', {
label: "who We Are",
multiline: true
}),
PropertyPaneTextField('OurValue', {
label: "Our value"
}), PropertyPaneTextField('description', {
label: "Description",
multiline: true
}),
]
}
]
}
]
};
}
}
inside the MyModalPopup.tsx:-
import * as React from 'react';
import { IMyModalPopupProps } from './IMyModalPopupProps';
import { DefaultButton } from '#fluentui/react/lib/Button';
import { MYModal } from './MYModal';
import { MYModal2 } from './MYModal2';
interface IPopupState {
showModal: string;
}
export default class MyModalPopup extends React.Component<IMyModalPopupProps, IPopupState> {
constructor(props: IMyModalPopupProps, state: IPopupState) {
super(props);
this.state = {
showModal: ''
};
this.handler = this.handler.bind(this);
this.Buttonclick = this.Buttonclick.bind(this);
}
handler() {
this.setState({
showModal: ''
})
}
private Buttonclick(e, whichModal) {
e.preventDefault();
this.setState({ showModal: whichModal });
}
public render(): React.ReactElement<IMyModalPopupProps> {
const { showModal } = this.state;
return (
<div>
<DefaultButton onClick={(e) => this.Buttonclick(e, 'our-value')} text="Our Value" />
{ showModal === 'our-value' && <MYModal2 OurValue={this.props.OurValue} myprops={this.state} handler={this.handler} />}
<DefaultButton onClick={(e) => this.Buttonclick(e, 'who-we-are')} text="Who We Are" />
{ showModal === 'who-we-are' && <MYModal WhoWeAre={this.props.WhoWeAre} myprops={this.state} handler={this.handler} />}
</div>
);
}
}
Actually, html-react-parser returns ReactJs object, and its return type is like React.createElement or like type of called JSX.
Using DOMPurify.sanitize will return safe pure HTML elements which those are different to the object that html-react-parser returns. the risxss ESLint plugin will force you to use sanitizing with any kind of sanitize function or library, that I left an answer to your other question to how to Sanitize your string HTML.
Eventually, using sanitizing is better because is the html-react-parser will convert your string HTML to ReactJs object with some tiny changes that would be dangerous because it is possible to have some script of string HTML in the project and it maybe will be harmful it just remove the onclick or onload, etc, from HTML tags but sanitizing will remove all possible harmful tags. also sanitizing will receive configuration, which means you can have your own options for sanitizing.

How to make Data and Vuex reactive?

There is such a code:
<template>
<div class="chart"
v-bind:style="chartStyleObject">
</div>
</template>
<script>
export default{
data () {
return {
chartStyleObject: {
width: this.$store.state.chartStyleObject.width,
height: this.$store.state.chartStyleObject.height,
marginTop: this.$store.state.chartStyleObject.marginTop,
marginRight: this.$store.state.chartStyleObject.marginRight,
marginBottom: this.$store.state.chartStyleObject.marginBottom,
marginLeft: this.$store.state.chartStyleObject.marginLeft,
},
},
}
}
And such a repository:
const axios = require("axios");
export const state = () => ({
chartStyleObject: {
height: '247px',
width: '500px',
marginTop: '15px',
marginRight: '0px',
marginBottom: '0px',
marginLeft: '15px',
},
});
export const mutations = {
changeChartDraggableEventState (state, EventState) {
state.chartDraggableEventState = EventState;
},
changeChartHeight (state, height) {
state.chartStyleObject.height = height;
},
changeHeightWrapper (state, HeightWrapper) {
state.chartStyleObject.HeightWrapper = HeightWrapper;
},
changeWidthWrapper (state, WidthWrapper) {
state.chartStyleObject.WidthWrapper = WidthWrapper;
},
changeChartMarginLeft (state, MarginLeft) {
state.chartStyleObject.marginLeft = MarginLeft;
},
changeChartMarginTop (state, MarginTop) {
state.chartStyleObject.marginTop = MarginTop;
},
};
Problem:
If I change the state of the repository through mutations, then the properties of the repository change correctly.
But!
The data properties on which the same storage properties are tied for some reason does not change.
(Despite the fact that repository property was changed)
My question is:
Why does this happen - if dates property, as well as repositories property, in theory, should be reactive?
And which approach is the most correct in this case to solve this problem? (writing directly the storage properties in the code seems like a very cumbersome decision.)
When you assign the values in
chartStyleObject: {
width: this.$store.state.chartStyleObject.width, // here
height: this.$store.state.chartStyleObject.height,
marginTop: this.$store.state.chartStyleObject.marginTop,
marginRight: this.$store.state.chartStyleObject.marginRight,
marginBottom: this.$store.state.chartStyleObject.marginBottom,
marginLeft: this.$store.state.chartStyleObject.marginLeft,
},
you are assigning values to the width, height and so on. You assign to them the current values of the state variables.
If you want the properties of chartStyleObject to change whenever the store's state changes, either map the state directly in the template (or wheverever you use it) or create a computed:
export default {
computed: {
chartStyleObject() {
return {
width: this.$store.state.chartStyleObject.width,
height: this.$store.state.chartStyleObject.height,
marginTop: this.$store.state.chartStyleObject.marginTop,
marginRight: this.$store.state.chartStyleObject.marginRight,
marginBottom: this.$store.state.chartStyleObject.marginBottom,
marginLeft: this.$store.state.chartStyleObject.marginLeft,
};
},
},
}

style binding by #click - vue.js

I am toggling one element and at that time, want to bind style another element. But I didn't understand how to achieve this with #click
data(){
return {
show:false,
filterStyle: {
top: 0,
background: "#dfe4ea",
marginTop: "15px",
marginBottom: "15px",
},
}
}
methods: {
closing(){
this.show = !this.show
},
}
<p class="closeMap" #click="closing()">close</p>
closing div below.
<div v-show="!show"></>
changing styles div below.
<div :style="filterStyle" class="filter"></div>
Is there someone can explain it to me?
Edit: By the way, as you see I am binding my styles, no problem with that. But not by #click... I want to bind those styles by #click.
I don't know if you want to add style on show or !show, anyway you can achieve it in this way:
<div :style="show ? filterStyle : null" class="filter"></div>
filterStyle will be applied only when show is true
I guess you could make a computed property, which changes based on this.show:
// Template
<div :style="filterStyle" class="filter"></div>
// Computed property
computed: {
filterStyle() {
if (this.show) {
return {
top: 0,
background: '#dfe4ea',
marginTop: '15px',
marginBottom: '15px'
};
} else {
return '';
}
}
}
You could also set filterStyle to something else in the click function

Is it possible to bind the inline style with vue.js?

I am curious, is it possible to bind the inline style in Vue.js? I'm familiar with class binding but what if sometimes for some reason you want to bind a style statement inline, is it possible to bind it like you do with class?
For example:
<template>
<div>
<h1 :style="{('background:red') : condition}"> Text </h1>
<button #click='condition = true'>Click me</button>
</div>
</template>
<script>
export default {
data() {
return {
condition: false,
};
},
};
</script>
In the example above I'd like to change the background of the element when the condition becomes true.
Of course it is possible as described here: https://v2.vuejs.org/v2/guide/class-and-style.html
<template>
<div>
<h1 v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"> Text </h1>
<button #click='condition = true'>Click me</button>
</div>
</template>
<script>
export default {
data() {
return {
condition: false,
activeColor: 'white',
fontSize: 12,
};
},
};
</script>
Yes, it's possible please go through the docs
Note: please use computed, methods instead of inline for better debugging
<template>
<div>
<h1 :style="styleObject"> Text </h1>
<button #click='toggleCondition'>Click me</button>
</div>
</template>
<script>
export default {
data() {
return {
condition: false,
};
},
computed: {
styleObject() {
return this.condition ? { background: 'red' } : {};
},
},
methods: {
toggleCondition() {
this.condition = !this.condition;
},
},
};
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

Categories