Type '{ children: never[]; title: string; content: Element; }' is not assignable to type 'IntrinsicAttributes & { title: any; }' - frontend

I am working on react website in typescript. I am using polaris wizard component, for that I have made on custom component called in which want to pass two arguments. but when I am calling that component in wizard.tsx , I am getting below error in .tsx file where I am using that component (i.e wizard.tsx).
Type '{ children: never[]; title: string; content: Element; }' is not assignable to type 'IntrinsicAttributes & { title: any; }'.
Property 'children' does not exist on type 'IntrinsicAttributes & { title: any; }'.
//wizard.tsx (file in which <CustomContainer> has been called.)
<CustomContainer
title = {"Organization information"}
content= {
<div>
Name of organisation
</div>
</div>
}
>
</CustomContainer>
//Wizard.tsx
const CustomContainer = ({title}:{title:any}, {content}:{content:any}) => {
return (
<Container
header={
<Header
variant="h2"
>
{title}
</Header>
}
>
{content}
</Container>
);
}
export default CustomContainer;
Any suggestions what I am missing?

This is not how attributes should be passed. It should work if you change customContainer to this.
const CustomContainer = ({ content, title }: { content: any; title: any }) => {
return <div id={title}>{content}</div>;
};

Related

Can't get html element using js file in SPFX

I am trying to build dynamic content from a SharePoint list using SPFX. I'd like to use jQuery to build an accordion view of the data. The issue is that I can't even seem to get the element once the page is rendered.
In my code I am requiring a file called ota.js with the following code:
console.log('Start');
function otaExpand(){
console.log('otaExpand Function Called');
let spListContainer = document.getElementById('spListContainer');
console.log(spListContainer);
}
window.addEventListener("load", otaExpand());
In my ts file this is my render method:
public render(): void {
this.domElement.innerHTML = `
<div>
<div id="spListContainer">TEST</div>
</div>
`;
//this._renderListAsync();
//($('.accordion', this.domElement) as any).accordion();
}
When I review the console, I get my messages, but the element itself comes back as null.
console.log
I am using SharePoint 2019 on premise with the following configuration.
+-- #microsoft/generator-sharepoint#1.10.0
+-- gulp-cli#2.3.0
`-- yo#2.0.6
node --version
v8.17.0
I should also mention I am using TypeScript with no JavaScript framework.
Does anyone know why I can't access this element from my js file?
Thanks!
My overall goal is to call list data and apply an accordion style to it (https://jqueryui.com/accordion), but I can't even get passed capturing the element to change it.
I've tried calling my code from a js file as well as trying to put the code directly in the html. Neither worked.
OK, I finally figured out what I was doing wrong. I was calling my jQuery in the render() method rather than in _renderList where this.domElement actually makes sense.
Here's my code in case anyone wants to avoid the pain I put myself through. This allows you to specify a list in the site and you just need to add the fields you want to display.
import { Version } from '#microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneChoiceGroupOption,
IPropertyPaneConfiguration,
PropertyPaneChoiceGroup,
PropertyPaneCustomField,
PropertyPaneTextField
} from '#microsoft/sp-webpart-base';
import { escape } from '#microsoft/sp-lodash-subset';
import styles from './GetSpListItemsWebPart.module.scss';
import * as strings from 'GetSpListItemsWebPartStrings';
import {
SPHttpClient,
SPHttpClientResponse
} from '#microsoft/sp-http';
import * as jQuery from 'jquery';
import 'jqueryui';
import { SPComponentLoader } from '#microsoft/sp-loader';
import PropertyPane from '#microsoft/sp-webpart-base/lib/propertyPane/propertyPane/PropertyPane';
export interface IGetSpListItemsWebPartProps {
title: string;
description: string;
listField: string;
}
export interface ISPLists {
value: ISPList[];
}
export interface ISPList {
ID: string;
Title: string;
Website: {
Description : string,
Url : string
};
Description : string;
}
export default class GetSpListItemsWebPart extends BaseClientSideWebPart<IGetSpListItemsWebPartProps> {
private _getListData(): Promise<ISPLists> {
return this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl + "/_api/web/lists/GetByTitle('" + this.properties.listField + "')/Items",SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => {
return response.json();
});
}
private _renderListAsync(): void {
this._getListData()
.then((response) => {
this._renderList(response.value);
})
.catch(() => {});
}
private _renderList(items: ISPList[]): void {
let listData = `
<h1>${this.properties.title}</h1>
<h2>${this.properties.description}</h2>
<div class="accordion">
`;
items.forEach((item: ISPList) => {
let Description : string;
item.Description ? Description = item.Description : Description = "";
listData += `
<h3> ${item.Title}</h3>
<div>
<table>
<tr>
<td>OTA URL</td>
<td>${item.Website.Description}</td>
</tr>
<tr>
<td>Description</td>
<td>${Description}</td>
</tr>
</table>
</div>
`;
});
listData += '</div>';
this.domElement.innerHTML = listData;
const accordionOptions: JQueryUI.AccordionOptions = {
animate: true,
collapsible: true,
icons: {
header: 'ui-icon-circle-arrow-e',
activeHeader: 'ui-icon-circle-arrow-s'
}
};
jQuery('.accordion', this.domElement).accordion(accordionOptions);
}
public render(): void {
this._renderListAsync();
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('title',{
label: strings.TitleFieldLabel
}),
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
}),
PropertyPaneTextField('listField', {
label: strings.ListFieldLabel
})
]
}
]
}
]
};
}
public constructor() {
super();
SPComponentLoader.loadCss('//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css');
}
}
Your code from the "ota.js" file is probably called before your HTML is initialized (i.e. before the "render()" function is executed). To make sure this is the case, you could add log to the "render()" function to see when it's called.
In other words, "window.load" event happens long before "render()" function is called. This is how web parts are loaded - dynamically after full load of the page. Or "window.load" does not happen at all - web parts may be loaded by the user when using the page designer, i.e. without page reload.
To fix the issue, you should get the element after it's created, i.e. after the "render()" function creates the element you are trying to get.

NextJS per page layout not working with typescript

I am developing new application in NextJS 12 using typescript. I have defined two pages register and home page and i want to apply different layout to this pages, i have followed official next js documentation for this, i can see the "Registration Page" text in browser but layout not applying on page output, am i missing something in code? below is my code.
register.tsx
const UserRegistration: NextPageWithLayout = () => {
return <h1>Registration Page</h1>
}
UserRegistration.getLayout = (page: ReactElement) => {
return (
<DefaultLayout>{page}</DefaultLayout>
)
}
export default UserRegistration;
_app.tsx
function MyApp({ Component, pageProps }: AppPropsWithLayout) {
const getLayout = Component.getLayout || ((page) => page)
return getLayout(<Component {...pageProps} />)
}
export default MyApp
type.ts
export type NextPageWithLayout = NextPage & { getLayout: (page: ReactElement) => ReactNode };
export type AppPropsWithLayout = AppProps & { Component: NextPageWithLayout }
export type DefaultLayoutType = { children: ReactNode }
layout.tsx
const DefaultLayout = ({ children }: DefaultLayoutType) => {
return(
<div id="main">
<nav>
<li>
Home
</li>
</nav>
{children}
</div>
)
}
export default DefaultLayout;

v-model cannot be used on v-for

VueCompilerError: v-model cannot be used on v-for or v-slot scope variables because they are not writable. Why?
<template>
<div v-for="service in services" :key="service.id">
<ServicesItem v-model="service"></ServicesItem >
</div>
</template>
<script lang="ts">
import ServicesItem from "#js/components/ServicesItem.vue"
export default defineComponent({
components: { ServicesItem },
setup() {
const services = ref([
{
id: 1,
name: "Service 1",
active: false,
types_cars: {
cars: {},
suv: {},
},
},
])
return {
services,
}
},
})
</script>
What are the best practices? Reactive object transfers
Okay, so what's going on is that the variable "service" is, let's say, virtual.
It doesn't exist, it's just a part of your real object "services" at a certain point (iteration).
If you'd like to "attach" that iteration to your component, you need to provide a real object, and in your case that would be done like that:
<div v-for="(service, i) in services" :key="service.id">
<ServicesItem v-model="services[i]"></ServicesItem >
</div>
Same issue here, i've change the modelValue props by an other custom props, and it works fine for me.
old:
const props = defineProps({
modelValue: {
type: Object,
required: true
}
})
NEW:
const props = defineProps({
field: {
type: Object,
required: true
}
})
Component:
<MyComponent :field="service"/>
instead of
<MyComponent :v-model="service"/>

Shallow component not updating on jest.fn call

After updating a series of dependencies, most notably jest and react/react-dom, a once working Unit Test is no longer working. After spending the last week reading through the ChangeLogs of the dependencies that changed, I still cannot find out why it is breaking.
The Component - stripped down for the relevant portions
[imports, etc.] ->not code, just giving a stripped down version
class MyComponent extends React.Component {
render() {
const { Foo, errorNotice, disabled } = this.props;
return (
<form autoComplete="Off">
<Paper className="top-paper edit-form">
<h1>{ Foo.id ? 'Edit' : 'Add' } My Foo </h1>
<div className="flex">
<div className="flex-column">
<FormControl
className="has-columns"
component="fieldset"
>
<TextField
id="foo-name"
fullWidth={true}
disabled={disabled}
name="name"
inputProps={{ maxLength: 50 }}
className="block"
label="Name"
value={Foo.name}
onChange={this.props.onChange}
error={!!errorText.name}
helperText={errorText.name}
/>
[closing tags, etc.] -> as as above, not code, just giving a stripped down version
export default MyComponent
The Test
import React from 'react';
import { shallow } from 'enzyme';
import MyComponent from "./my-component";
const Foo = {
name: 'Foo Name',
val_x: 'NONE'
};
const handleTextChange = jest.fn(({ target: { name, value} }) => {
Foo[name] = value;
testMyComponent.setProps({ Foo });
});
const testMyComponent = shallow(
<MyComponent
Foo={Foo}
errorNotice={{}}
onChange={handleTextChange}
/>
);
describe('Test component display', () => {
it('Name field show display attachment point name', () => {
const nameInput = testMyComponent.find('[name="name"]');
expect(nameInput.props().value).toBe(Foo.name);
});
});
^^ This Test Passes
describe('Test Foo interactions', () => {
it('Updating Name field should update Foo name', () => {
const newName= 'New Name';
testMyComponent.find('[name="name"]').simulate('change', {
target: { name: "name", value: newName }
});
expect(testMyComponent.find('[name="name"]').props().value).toBe(newName);
});
});
^^ This Test Fails on the 'expect' line. The name remains the old name, 'Foo Name'
The output when I call testMyComponent.debug() after the .simulate('change' is as follows (again stripped down)
<WithStyles(ForwardRef(TextField)) id="foo-name" fullWidth={true} disabled={[undefined]} name="name" inputProps={{...}} className="block" label="Name" value="Foo Name" onChange={[Function: mockConstructor] { _isMockFunction: true, ... , results: [ Object [Object: null prototype] {type: 'return', value: undefined } ], lastCall: [ { target: { name: 'name', value: 'New Name' ....
^^ So I can see through lastCall that the handleTextChange function is being called, but its not actually performing the update. Moreover, if I put a test for
expect(handleTextChange).toHaveBeenCalledTimes(1);
Then that text passes, it effectively gets called. But again, the update doesn't actually occur.
The dependencies that were changed were
react 16.13.1 -> 17.0.2
react-dom 16.13.1 -> 17.0.2
jest 24.9.0 -> 27.5.1
material-ui/core 4.11.0 -> 4.12.13
but enzyme stayed the same a 3.11.0
Does any of this make any sense? Like I mentioned I've read changelogs and update posts on all of the dependencies that were updated and I cant see anything that needs to change in the test, but clearly it is failing. I have read Jest/Enzyme Shallow testing RFC - not firing jest.fn() but the solution there is not working for me. I should also mention I have called .update() on the component but to no avail.

Typescript wrong type with Material-UI Higher Order Components

I'm trying to update from Material-UI 1.x to Material-UI 3.9.2.
I had a few components, including the example below, that were working properly with Higher Order Components (HOC), but I have a hard time at migrating them to 3.9.2.
In this example, I reduced a problem and don't get why the typings are wrong (Typescript 3.3.3). It seems to me to be consistent with the way MUI PropInjector works.
Here is an example:
import { createStyles, Theme, withStyles, WithStyles } from '#material-ui/core';
import Dialog, { DialogProps } from '#material-ui/core/Dialog';
const styles = (theme: Theme) => createStyles({
defaultPaperWidthSm: {
backgroundColor: "#fafafa",
minWidth: 320,
maxWidth: 700
},
largePaperWidthSm: {
backgroundColor: "#fafafa",
width: 700,
maxWidth: 700,
[theme.breakpoints.up('md')]: {
minWidth: 900,
width: "unset",
maxWidth: "80vw",
}
}
})
export default withStyles(styles)(
function ResponsiveDialog(props: DialogProps & WithStyles<typeof styles>) {
let { classes, className, ...otherProps } = props
return <Dialog {...otherProps} />
}
)
Using it as a component:
<ResponsiveDialog open={true}>
<span>Blabla</span>
</ResponsiveDialog>
It returns this error, and I don't get why:
Type '{ children: Element; open: boolean; }' is not assignable to type 'IntrinsicAttributes & Pick & StyledComponentProps<"defaultPaperWidthSm" | "largePaperWidthSm"> & { children?: ReactNode; }'.
Property 'open' does not exist on type 'IntrinsicAttributes & Pick & StyledComponentProps<"defaultPaperWidthSm" | "largePaperWidthSm"> & { children?: ReactNode; }'.
Found it!
It's working if I use an arrow function:
export default withStyles(styles)(
(props: DialogProps & WithStyles<typeof styles>) => {
let { classes, className, ...otherProps } = props
return <Dialog {...otherProps} />
}
)
There are still issues when I combine multiple HOC, I have the feeling MUI typings are currently a bit broken. But it's another problem.

Resources