I've setup vue3 and Oruga but am running into some difficutly when attempting to get the component to render. The table component is displayed within a router-view (view/Vehicles)
I have:
/view/Vehicles.
<template>
<h1>Vehicles</h1>
<o-table :data="vehicles" :columns="columns"></o-table>
</template>
<script>
import { Table } from '#oruga-ui/oruga-next'
import { API } from 'aws-amplify'
import { listVehicles } from '../graphql/queries'
export default {
name: "Vehicles",
components: {
'o-table': Table
},
data() {
return {
vehicles: [],
columns: [
{
field: 'id',
label: 'ID',
width: '40',
numeric: true
},
{
field: 'name',
label: 'Name'
},
{
field: 'description',
label: 'Description'
},
{
field: 'address',
label: 'Address',
position: 'centered'
}
]
}
},
methods: {
/*
* Load async data
*/
async listVehicles() {
console.log("Getting Vehicles...")
const vehicles = await API.graphql({ query: listVehicles})
this.vehicles = vehicles.data.listVehicles.items
},
/*
* Handle page-change event
*/
onPageChange(page) {
this.page = page
this.listVehicles()
},
/*
* Handle sort event
*/
onSort(field, order) {
this.sortField = field
this.sortOrder = order
this.listVehicles()
},
/*
* Type style in relation to the value
*/
type(value) {
const number = parseFloat(value)
if (number < 6) {
return 'is-danger'
} else if (number >= 6 && number < 8) {
return 'is-warning'
} else if (number >= 8) {
return 'is-success'
}
}
},
mounted() {
this.listVehicles()
}
}
</script>
<style>
</style>
main.js - bootstrapping entire oruga library, doesn't seem to make a difference if I use single component or not...
import { createApp } from "vue";
import App from "./App.vue";
import Amplify from "aws-amplify";
import awsconfig from "./aws-exports";
import Oruga from "#oruga-ui/oruga-next";
import "./index.css";
import {
applyPolyfills,
defineCustomElements,
} from "#aws-amplify/ui-components/loader";
import router from "./router";
applyPolyfills().then(() => {
defineCustomElements(window);
});
Amplify.configure(awsconfig);
createApp(App).use(router).use(Oruga).mount("#app");
Looks like it was two things, need to add async to mounted as also the blocking warning was coming from eslinter set to
"rules": {
"vue/no-unused-components": "off"
}
Related
I have a vue 3 script setup component (composition api), and another file (for printing) that has some logic I want to inject into my main component.
My main file looks like
<template>
<v-app>
<v-main>
<v-table-mobile :headers="headers" :rows="rows" :items-per-page="itemsPerPage" no-data-text="No data to display" pagination-text="{0} - {1} of {2}" :sort-by="sortBy" :group-by="groupBy">
<template #item.a="{ item }">
{{ item.a }}
</template>
</v-table-mobile>
</v-main>
</v-app>
</template>
<script lang="ts">
import * as Print from './utils/print';
export Print;
</script>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import VTableMobile, { TableHeader, TableColumnSort, TableColumnGroup } from './components/MobileTable.vue';
const sortBy = ref({key:'a', order:'asc'} as TableColumnSort);
//const sortBy = ref({} as TableColumnSort);
const groupBy = ref({key:'a', expanded:[1] as any[]} as TableColumnGroup);
//const groupBy = ref({} as TableColumnGroup);
const itemsPerPage = ref(3);
const headers = ref([
{ key: "a", title: "a" },
{ key: "b", title: "b" }
] as TableHeader[]);
const rows = ref([
{ a:1, b:2 },
{ a:3, b:4 },
{ a:1, b:6 },
{ a:7, b:8 },
{ a:9, b:10 },
{ a:11, b:12 },
{ a:13, b:14 },
{ a:15, b:16 },
{ a:17, b:18 },
{ a:19, b:20 }
]);
onMounted(() => {
setTimeout(() => {
rows.value = rows.value.concat([ { a:21, b:22 } ]);
itemsPerPage.value = 4;
}, 3000);
})
</script>
The print file looks like
import { Ref, nextTick } from 'vue';
export default {
mounted() {
alert(1);
},
beforeUnmount() {
alert(2);
},
methods: {
async Print(print_mode:Ref<boolean>) {
print_mode.value = true;
await nextTick();
window.print();
},
DisablePrintMode(print_mode:Ref<boolean>) {
print_mode.value = false;
}
}
}
I want to add the mounted, beforeMount and the 2 methods to be injected into my main component. But this is not working. How can I fix it?
Right now I get an error
Declaration or statement expected.ts(1128) where the export Print is.
Thanks
Vue composables are designed for this.
Composables | VueJS
<!-- print file -->
<script setup>
import { onMounted, onUnmounted, nextTick } from 'vue'
/*
Other logic code
*/
async function Print(print_mode) {
print_mode.value = true;
await nextTick();
window.print();
},
function DisablePrintMode(print_mode) {
print_mode.value = false;
}
onMounted(() => {
// content of this hook
})
onUnmounted(() => {
// content of this hook
})
</script>
<!-- main file -->
<script setup>
import { usePrint } from './print.js'
const printFunc = usePrint()
</script>
I have written a sample code, you can take this reference to your code
I am able to fetch the list which we see on the landing screen of the site-content. However, when I am trying to fetch data by finding a particular item by its title I get an error CANNOT FIND LIST 'EmployeeList' IN THE URL.
I have built a React Web-part and here are the files and code
ListOfSprintStories.tsx
private _getListData(): Promise<ISPLists> {
return this.props.context.spHttpClient.get(this.props.context.pageContext.web.absoluteUrl + `/_api/web/lists/GetByTitle('EmployeeList')/Items`, SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => {
return response.json();
});
}
private _renderListAsync(): void {
// Local environment
if (Environment.type === EnvironmentType.Local) {
this._getMockListData().then((response) => {
this.setState({ finalList: response.value });
});
}
else if (Environment.type == EnvironmentType.SharePoint ||
Environment.type == EnvironmentType.ClassicSharePoint) {
this._getListData()
.then((response) => {
console.log('======>', response.value)
this.setState({ finalList: response.value });
});
}
}
componentDidMount() {
this._renderListAsync()
}
IListOfSprintStoriesProps.ts
import { WebPartContext } from '#microsoft/sp-webpart-base';
export interface IListOfSprintStoriesProps {
description: string;
context: WebPartContext;
}
ListOfSprintStoriesWebPart.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 'ListOfSprintStoriesWebPartStrings';
import ListOfSprintStories from './components/ListOfSprintStories';
import { IListOfSprintStoriesProps } from './components/IListOfSprintStoriesProps';
import { WebPartContext } from '#microsoft/sp-webpart-base';
export interface IListOfSprintStoriesWebPartProps {
description: string;
context: WebPartContext;
}
export default class ListOfSprintStoriesWebPart extends BaseClientSideWebPart<IListOfSprintStoriesWebPartProps> {
public render(): void {
const element: React.ReactElement<IListOfSprintStoriesProps> = React.createElement(
ListOfSprintStories,
{
description: this.properties.description,
context: this.context
}
);
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('description', {
label: strings.DescriptionFieldLabel
})
]
}
]
}
]
};
}
}
I have followed the documentation.
https://learn.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/connect-to-sharepoint
I was able to fetch the complete site content list(Document library), but when I am trying to fetch a particular list using getByTitle('EmployeeList'), it fails.
Here is the error message:
{"error":{"code":"-1, System.ArgumentException","message":"List 'EmployeeList' does not exist at site with URL 'https://myTenant.sharepoint.com'."}}
Please Advice.
Issue fixed: The WebPart was working fine locally by fetching data from _getMockListData.
However, it wasn't when I was trying to test the WebPart on the https://MyOffice365.sharepoint.com/sites/**InCorrectSPSite**/_layouts/15/workbench.aspx
I later noticed that I was pointing to wrong SP-site.
I've used vue create to setup a new Vue project, and have installed Storybook - all working correctly.
I have then installed storybook-addon-designs and followed the readme on adding to my story, but it gives me the following error in my console: h is not defined.
Here's my files:
stories/2-PageTitle.stories.js:
import { withDesign } from 'storybook-addon-designs'
import {Button} from '../src/components/Button'
export default {
title: 'My stories',
component: Button,
decorators: [withDesign]
}
export const myStory = () => <Button>Hello, World!</Button>
myStory.story = {
name: 'My awesome story',
parameters: {
design: {
type: 'figma',
url: 'https://www.figma.com/file/LKQ4FJ4bTnCSjedbRpk931/Sample-File'
}
}
}
babel.config.js:
module.exports = {
presets: [
'#vue/cli-plugin-babel/preset'
]
}
.storybook/main.js:
module.exports = {
stories: ['../stories/**/*.stories.js'],
addons: ['storybook-addon-designs']
};
src/components/Button.vue:
<template>
<button>
{{ label }}
</button>
</template>
<script>
export default {
name: 'Button',
props: {
label: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
button {
background: red;
}
</style>
Can anyone see what I'm doing wrong here?
Full code here (I'd of done a Sandbox but because it uses Storybook this seems like a better way?): https://github.com/A7DC/storybookvueaddonstest
The author of storybook-addon-designs suggests the following:
You have to replace the export
const myStory = () => <Button>Hello, World!</Button>
You need to change this line (React story) to Vue's one. For example,
export const myStory = () => ({
components: { Button },
template: '<Button>Hello, World!</Button>'
})
Updated answer -
import { withDesign } from "storybook-addon-designs";
import Button from "../src/components/Button";
export default {
title: "My Stories",
decorators: [withDesign],
};
export const myStory = () => ({
components: { Button },
template: "<Button> Hello, World!</Button >",
});
myStory.story = {
name: "My awesome story",
parameters: {
design: {
type: "figma",
url: "https://www.figma.com/file/LKQ4FJ4bTnCSjedbRpk931/Sample-File",
},
},
};
I want to display data from API with highcharts but still get an error because highchart config declared outside the class app and data fetched inside class app.
It works if use static data,
here is the example from static data link.
import React, { Component } from 'react';
import { render } from 'react-dom';
import ReactHighstock from 'react-highcharts/ReactHighstock';
import './style.css';
const data = [
[1220832000000, 22.56], [1220918400000, 21.67], [1221004800000,
21.66], [1221091200000, 21.81], [1221177600000, 21.28],
[1221436800000, 20.05], [1221523200000, 19.98], [1221609600000,
18.26], [1221696000000, 19.16], [1221782400000, 20.13],
[1222041600000, 18.72], [1222128000000, 18.12], [1222214400000,
18.39], [1222300800000, 18.85], [1222387200000, 18.32],
[1222646400000, 15.04], [1222732800000, 16.24], [1222819200000,
15.59], [1222905600000, 14.3], [1222992000000, 13.87],
[1223251200000, 14.02], [1223337600000, 12.74], [1223424000000,
12.83], [1223510400000, 12.68], [1223596800000, 13.8],
[1223856000000, 15.75], [1223942400000, 14.87], [1224028800000,
13.99], [1224115200000, 14.56], [1224201600000, 13.91],
[1224460800000, 14.06], [1224547200000, 13.07], [1224633600000,
13.84], [1224720000000, 14.03], [1224806400000, 13.77],
[1225065600000, 13.16], [1225152000000, 14.27], [1225238400000,
14.94], [1225324800000, 15.86], [1225411200000, 15.37],
[1225670400000, 15.28], [1225756800000, 15.86], [1225843200000,
14.76], [1225929600000, 14.16], [1226016000000, 14.03],
[1226275200000, 13.7], [1226361600000, 13.54], [1226448000000,
12.87], [1226534400000, 13.78], [1226620800000, 12.89],
[1226880000000, 12.59], [1226966400000, 12.84], [1227052800000,
12.33], [1227139200000, 11.5], [1227225600000, 11.8],
[1227484800000, 13.28], [1227571200000, 12.97], [1227657600000,
13.57], [1227830400000, 13.24], [1228089600000, 12.7],
[1228176000000, 13.21], [1228262400000, 13.7], [1228348800000,
13.06], [1228435200000, 13.43], [1228694400000, 14.25],
[1228780800000, 14.29], [1228867200000, 14.03], [1228953600000,
13.57], [1229040000000, 14.04], [1229299200000, 13.54]
];
const config = {
rangeSelector: {
selected: 1
},
title: {
text: 'aAAPL Stock Price'
},
series: [{
name: 'AAPL',
data: data,
tooltip: {
valueDecimals: 2
}
}]
};
class App extends Component {
render() {
return (
<div className="App" />
);
}
}
render(<ReactHighstock config={config}/>,
document.getElementById('root'));
With example above, two variable data and config placed outside the class app, so i think it's not problem.
But if i want to fetch data from API, the data placed inside the class app and config still outside class app.
So i get an error 'data is not defined'
here is the link
import React, { Component } from 'react';
import { render } from 'react-dom';
import ReactHighstock from 'react-highcharts/ReactHighstock';
import './style.css';
const config = {
rangeSelector: {
selected: 1
},
title: {
text: 'aAAPL Stock Price'
},
series: [{
name: 'AAPL',
data: data,
tooltip: {
valueDecimals: 2
}
}]
};
class App extends Component {
constructor() {
super();
this.state = {
dataResults: [],
}
}
componentDidMount() {
this.getData();
}
getData = () => {
fetch('https://cdn.rawgit.com/highcharts/highcharts/057b672172ccc6c08fe7dbb27fc17ebca3f5b770/samples/data/usdeur.json')
.then(res => res.json())
.then(data => {
this.setState({
dataResults: data
});
});
}
render() {
return (
<div className="App" />
);
}
}
render(<ReactHighstock config={config}/>,
document.getElementById('root'));
How to use highcharts with fetched data from API?
Your App component is currently not part of your DOM as you're rendering ReactHighstock as a root component. One solution would be to render the chart inside the App component and pass the data dynamically:
const getConfig = data => ({
rangeSelector: {
selected: 1
},
title: {
text: 'aAAPL Stock Price'
},
series: [{
name: 'AAPL',
data: data,
tooltip: {
valueDecimals: 2
}
}]
});
class App extends Component {
constructor() {
super();
this.state = {
dataResults: [],
}
}
componentDidMount() {
this.getData();
}
getData = () => {
fetch('your_endpoint_url')
.then(res => res.json())
.then(data => {
this.setState({
dataResults: data
});
});
}
render() {
const { dataResults } = this.state;
const chartConfig = getConfig(dataResults);
return (
<ReactHighstock config={chartConfig}/>
);
}
}
render(<App/>,
document.getElementById('root'));
You should of course handle a use case where the data has not been fetched yet and display a placeholder.
I started to integrate a WYSIWYG into a blog project, I'm using Quill for this (I had no experience with it before). I was able to customize my editor the way it was required, what I don't understand is how to deal with text format and embed videos. I have two fields in my post form, "preview" and "content" (two quill editors) while introducing the text I can give format to it (header, italic, underline...etc) and when click the embed video option the editor allows me to add the link and visualize the embed video in that moment. When I press my save button it stores the post in my db but in my single post page I visualize all the fields without format (header, italic, underline...etc) and also no embed video. How can I give format and show the video? Any help would be appreciated.
I read the Quill documentation and tried to understand how to deal with this using deltas but I don't know how to make this work.
I'm using Meteor + React, this is my code (I'll show only relevant code):
This is my lib, quill.jsx
import React, { Component } from 'react';
import QuillLib from './vendor/quill.js';
import { ud } from '/helpers/lib/main.jsx';
class Quill extends Component {
constructor(props) {
super(props);
this.id = ud.shortUID();
}
componentDidMount() {
const that = this;
const toolbarOptions = [
[{ font: [] }],
[{ header: 1 }, { header: 2 }],
[{ header: [1, 2, 3, 4, 5, 6, false] }],
[{ align: [] }],
['bold', 'italic', 'underline', 'strike'],
['blockquote', 'code-block'],
[{ script: 'sub' }, { script: 'super' }],
[{ indent: '-1' }, { indent: '+1' }],
[{ color: [] }, { background: [] }],
['video'],
['image'],
];
const quill = new QuillLib(`#quill-editor-container-${this.id}`, {
modules: {
toolbar: toolbarOptions,
},
theme: 'snow',
});
const content = this.props.content;
quill.setContents(content);
quill.on('text-change', (delta) => {
if (that.props.onChange) {
that.props.onChange(quill);
}
});
}
render() {
return (
<div className="wysiwyg-wrapper">
<div id={`quill-editor-container-${this.id}`}></div>
</div>
);
}
}
export default Quill;
This is my input form component, list.jxs
import { Meteor } from 'meteor/meteor';
import { PostSchema } from '/modules/blog/lib/collections.jsx';
import Quill from '/modules/quill/client/main.jsx';
export class BlogCategory extends Component {
constructor(props) {
super(props);
this.state = {
post: {
content: '',
preview: '',
},
};
this.onPreviewChange = this.onPreviewChange.bind(this);
this.onContentChange = this.onContentChange.bind(this);
}
onPreviewChange(content) {
this.state.post.preview = content.getText();
this.setState(this.state);
}
onContentChange(content) {
this.state.post.content = content.getText();
this.setState(this.state);
}
save() {
const content = this.state.post.content;
const preview = this.state.post.preview;
const post = new PostSchema();
post.set({
content,
preview,
});
if (post.validate(false)) {
const id = post.save();
}
console.log(post.getValidationErrors(false));
}
renderCreatePostForm() {
let content;
if (this.state.showForm) {
content = (
<form action="">
<Quill
content={this.state.post.preview}
onChange={this.onPreviewChange}
/>
<Quill
content={this.state.post.content}
onChange={this.onContentChange}
/>
</form>
);
}
return content;
}
render() {
let content = (
<div className="col-xs-12">
{this.renderActions()}
</div>
);
if (!this.props.ready) {
content = <p>LOADING...</p>;
}
return content;
}
}
export default createContainer(() => {
const handleValidPost = Meteor.subscribe('posts');
return {
ready: handleValidPost.ready(),
posts: PostSchema.find({}).fetch(),
};
}, BlogCategory);
And finally my collections.jsx
import { Mongo } from 'meteor/mongo';
export const PostCollection = new Mongo.Collection('Posts');
export const PostSchema = Astro.Class({
name: 'PostSchema',
collection: PostCollection,
fields: {
content: {
validator : Validators.and([
Validators.required(),
Validators.string(),
Validators.minLength(3)
])
},
preview: {
validator : Validators.and([
Validators.required(),
Validators.string(),
Validators.minLength(3)
])
},
}
});
While getting Quill contents by getText, you lost your text format and video information. Using getText, all non-string data will be omitted. Quill data are defined as Delta (which is a JSON object).
You can fix this by updating your onPreviewChange and onContentChange to use getContents instead of getText. Save these Delta to DB and load it again.
onPreviewChange(content) {
this.state.post.preview = content.getContents();
this.setState(this.state);
}
onContentChange(content) {
this.state.post.content = content.getContents();
this.setState(this.state);
}