jQuery UI Widgets › Forums › React › jqxWindow events from content
This topic contains 15 replies, has 5 voices, and was last updated by QuarantineSelfies 3 years, 1 month ago.
-
Author
-
Hi,
The issue I have is my component with JQXWindow doesn’t produce events from html elements that are content of the window.
my environment Node v.14.16.0, React v.17.0.2.
I created new project with create-react-app with typescript and installed jqwidgets.
Then replaced content of App.tsx with example from JQXWindow API AutoOpen property
https://www.jqwidgets.com/react-components-documentation/documentation/jqxwindow/reactjs-window-api.htm?search=
The sample works fine. It shows Window with header “RISC”, and content with text and OK, Cancel buttons.
As expected nothing happens when clicking on buttons because no events wired to the buttons.
But nothing happens when clicking on buttons after I added onClick events to the buttons with logging to console.
I added text box (input element) end wired onKeyUp and onKeyPress events with logging to console.
Again these events are not fired.
Added JQXButton and wired onClick event. Event is fired when clicking on this element.What I am missing?
Why events from regular elements that are part of content of JQXWindow are not fired but it is fired form JQXButton.
What could be done in order to regular elements fired events?Thanks,
Hello vmlaskin,
I try to create the following code snippet below based on this tutorial:
App.tsx:import * as React from 'react'; import JqxButton from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxbuttons'; import JqxPanel from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxpanel'; import JqxWindow from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxwindow'; class App extends React.PureComponent<{}, any> { private myWindow = React.createRef<JqxWindow>(); private events = React.createRef<JqxPanel>(); constructor(props: {}) { super(props); this.showWindowButtonClick = this.showWindowButtonClick.bind(this); this.eventWindowClose = this.eventWindowClose.bind(this); this.eventWindowMoved = this.eventWindowMoved.bind(this); this.eventWindowOpen = this.eventWindowOpen.bind(this); } public render() { return ( <div> <JqxButton onClick={this.showWindowButtonClick} width={80}> Show </JqxButton> <div style={{ marginTop: 10 }}>Events Log:</div> <JqxPanel ref={this.events} style={{ border: 'none' }} width={450} height={250} /> <JqxWindow ref={this.myWindow} onClose={this.eventWindowClose} onOpen={this.eventWindowOpen} onMoved={this.eventWindowMoved} width={270} height={165} maxHeight={180} maxWidth={280} minHeight={30} minWidth={250} cancelButton={'.cancel'} okButton={'.ok'} resizable={false} isModal={true} modalOpacity={0.3} position={{ x: 90, y: 140 }} draggable={true} > <div> <img width="14" height="14" src="./../images/help.png" alt="" /> Modal Window </div> <div> <div> Please click "OK", "Cancel" or the close button to close the modal window. The dialog result will be displayed in the events log. </div> <div style={{ float: "right", marginTop: 15 }}> <div> <JqxButton className={'ok'} style={{ display: 'inline-block', marginRight: 10 }} width={80}> OK </JqxButton> <JqxButton className={'cancel'} style={{ display: 'inline-block' }} width={80}> Cancel </JqxButton> </div> </div> </div> </JqxWindow> </div> ); } private capitaliseFirstLetter(word: string): string { return word.charAt(0).toUpperCase() + word.slice(1); }; private displayEvent(event: any): void { let eventData = 'Event: ' + this.capitaliseFirstLetter(event.type); if (event.type === 'moved') { eventData += ', X: ' + event.args.x + ', Y: ' + event.args.y; } if (event.type === 'close') { eventData += ', Dialog result: '; if (event.args.dialogResult.OK) { eventData += 'OK'; } else if (event.args.dialogResult.Cancel) { eventData += 'Cancel'; } else { eventData += 'None'; } } this.events.current!.prepend('<div style="margin-top: 5px;">' + eventData + '</div>'); }; // Event handling private showWindowButtonClick(): void { this.myWindow.current!.open(); } private eventWindowClose(event: any): void { this.displayEvent(event); } private eventWindowMoved(event: any): void { this.displayEvent(event); } private eventWindowOpen(event: any): void { this.displayEvent(event); } } export default App;
It is based on this demo.
Best Regards,
Hristo HristovjQWidgets team
https://www.jqwidgets.comThanks for respond.
As I stated in my question, your demo samples work fine. I see that JQXButtons fired events from JqxWindow content.
Issue is started when I added regular buttons or textbox to the sample code.
Bellow is code with my changes where I added regular button (“My Button”) to JqxWindow content, added “Outside JqxWindow Button” outside JqxWindow content, and wired all buttons with onClick event. Also I commented JqxWindow properties cancelButton,okButton because I am not interested in open/close window events at this point.
Run this code and click on all buttons.
In my machine onClick event from regular button “My Button” is not fired. This button is in jqxWindow content.
All other buttons produce onClick events.import * as React from ‘react’;
import ‘jqwidgets-scripts/jqwidgets/styles/jqx.base.css’;
import JqxButton from ‘jqwidgets-scripts/jqwidgets-react-tsx/jqxbuttons’;
import JqxPanel from ‘jqwidgets-scripts/jqwidgets-react-tsx/jqxpanel’;
import JqxWindow from ‘jqwidgets-scripts/jqwidgets-react-tsx/jqxwindow’;class App extends React.PureComponent<{}, any> {
private myWindow = React.createRef<JqxWindow>();
private events = React.createRef<JqxPanel>();
constructor(props: {}) {
super(props);
this.showWindowButtonClick = this.showWindowButtonClick.bind(this);
this.eventWindowClose = this.eventWindowClose.bind(this);
this.eventWindowMoved = this.eventWindowMoved.bind(this);
this.eventWindowOpen = this.eventWindowOpen.bind(this);
this.onButtonClick=this.onButtonClick.bind(this);
}
public render() {
return (
<div>
<JqxButton onClick={this.onButtonClick} width={80}>
Show
</JqxButton>
<button onClick={this.onButtonClick} >
Outside JqxWindow Button
</button>
<div style={{ marginTop: 10 }}>Events Log:</div>
<JqxPanel ref={this.events}
style={{ border: ‘none’ }}
width={450} height={250}>
</JqxPanel>
<JqxWindow ref={this.myWindow}
onClose={this.eventWindowClose}
onOpen={this.eventWindowOpen}
onMoved={this.eventWindowMoved}
width={270}
height={165}
maxHeight={180}
maxWidth={280}
minHeight={30}
minWidth={250}
// cancelButton={‘.cancel’}
// okButton={‘.ok’}
resizable={false}
// isModal={true}
modalOpacity={0.3}
position={{ x: 90, y: 140 }}
draggable={true}
>
<div>
{/**/}
Modal Window
</div>
<div>
<div>
Please click “OK”, “Cancel” or the close button to close the modal window.
The dialog result will be displayed in the events log.
</div>
<div style={{ float: “right”, marginTop: 15 }}>
<div>
<JqxButton onClick={this.onButtonClick} className={‘ok’} style={{ display: ‘inline-block’ }} width={80}>
OK
</JqxButton>
<JqxButton onClick={this.onButtonClick} className={‘cancel’} style={{ display: ‘inline-block’ }} width={80}>
Cancel
</JqxButton>
<button onClick={this.onButtonClick} >
My Button
</button>
</div>
</div>
</div>
</JqxWindow>
</div>
);
}
private capitaliseFirstLetter(word: string): string {
return word.charAt(0).toUpperCase() + word.slice(1);
};
private displayEvent(event: any): void {
let eventData = ‘Event: ‘ + this.capitaliseFirstLetter(event.type);
if (event.type === ‘moved’) {
eventData += ‘, X: ‘ + event.args.x + ‘, Y: ‘ + event.args.y;
}
if (event.type === ‘close’) {
eventData += ‘, Dialog result: ‘;
if (event.args.dialogResult.OK) {
eventData += ‘OK’;
} else if (event.args.dialogResult.Cancel) {
eventData += ‘Cancel’;
} else {
eventData += ‘None’;
}
}
this.events.current!.prepend(‘<div style=”margin-top: 5px;”>’ + eventData + ‘</div>’);
};
// Event handling
private showWindowButtonClick(): void {
this.myWindow.current!.open();
}
private eventWindowClose(event: any): void {
this.displayEvent(event);
}
private eventWindowMoved(event: any): void {
this.displayEvent(event);
}
private eventWindowOpen(event: any): void {
this.displayEvent(event);
}
private onButtonClick(event: any): void {
let eventData =Event: ${this.capitaliseFirstLetter(event.type)} ${event.target.textContent}
;
this.events.current!.prepend(‘<div style=”margin-top: 5px;”>’ + eventData + ‘</div>’);
}
}export default App;
Hello vmlaskin,
Could you clarify it?
Because I click on the defaultbutton
and its event is fired.
What do you want to achieve, what is your final goal?
I look forward to hearing from you.Best Regards,
Hristo HristovjQWidgets team
https://www.jqwidgets.comthere are two “default” buttons in the code I sent you. One of them is outside jqxWindow and another is inside it.
the one that is inside jqxWindow (“My Button”) doesn’t produce events in my project.
I want to understand why no events from default elements inside jqxwindow in my project and what could be wrong/different in my project setup if it works on your side.
I followed steps for creating react project with jqwidgets.
https://www.jqwidgets.com/react-components-documentation/documentation/create-react-app/index.htm?search=1. created new project with create-react-app with typescript
2. install jqwidgets-script
My current environment: Node v.14.16.0, React v.17.0.2.I have jqwidgets v.5.6.0 based application where all default elements in jqxwindow content produce events. It is compiled in environment with Node v.8.5.0, React 16.3.1. Currently I am working on migration to the latest node, react, jqwidgets.
Hello vmlaskin,
The mentioned version of the jQWidgets is an older version.
There is a lot of improvements and updates.
In the example that I created with the Node v14.15.4, the npm v6.14.11, the React v16.8.6, and the jQWidgets v8.1.4.
I would like to suggest you update your project.Best Regards,
Hristo HristovjQWidgets team
https://www.jqwidgets.comMy goal is to migrate/upgrade my old application to the latest components versions.
I was wondering why you asked me to run example project with outdated jqwidgets.
I would expect you to test project on your side with the latest components as I asked in the first post.
Any way I proceed with example project and run it on my machine. And it works as expected. Default button from jqxwindow content fires even as expected.It only proves that old jqwidgets don’t have issues with outdated React and other outdated components from example project package.json.
Bellow is what I have after installing example project
yarn outdated
Package Current Wanted Latest Package Type URL
@types/jest 24.0.15 24.0.15 26.0.23 dependencies https://github.com/DefinitelyTyped/DefinitelyTyped.git
@types/node 12.0.8 12.0.8 15.0.1 dependencies https://github.com/DefinitelyTyped/DefinitelyTyped.git
@types/react 16.8.20 16.8.20 17.0.4 dependencies https://github.com/DefinitelyTyped/DefinitelyTyped.git
@types/react-dom 16.8.4 16.8.4 17.0.3 dependencies https://github.com/DefinitelyTyped/DefinitelyTyped.git
jqwidgets-scripts 8.3.2 8.3.2 12.0.4 dependencies https://www.jqwidgets.com/
react 16.14.0 16.14.0 17.0.2 dependencies https://reactjs.org/
react-dom 16.14.0 16.14.0 17.0.2 dependencies https://reactjs.org/
react-scripts 3.0.1 3.0.1 4.0.3 dependencies https://github.com/facebook/create-react-app#readme
typescript 3.5.2 3.5.2 4.2.4 dependencies https://www.typescriptlang.org/As I said, default button under jqxwindow content works fine when I run this project with outdated components.
Next, I upgraded all components to the latest versions. That is what I need for migration.
Events from default button under jqxwindow content stopped working after upgrading project to the latest versions.It tells me that latest jqxwidgets are incompatible most likely with latest React or/and less likely with other latest components.
Don’t see any restrictions on jqwidgets site for working with certain versions of React or Typescript.Below is list of components and their versions in package.json after upgrading the project.
yarn upgrade –latest
“dependencies”: {
“@types/jest”: “26.0.23”,
“@types/node”: “15.0.1”,
“@types/react”: “17.0.4”,
“@types/react-dom”: “17.0.3”,
“jqwidgets-scripts”: “^12.0.4”,
“react”: “^17.0.2”,
“react-dom”: “^17.0.2”,
“react-scripts”: “4.0.3”,
“typescript”: “4.2.4”
},Hello vmlaskin,
I am sorry about the late answer.
After the simple installation of the default React project I try to add the jQWidgets scripts as follow:
npm install jqwidgets-scripts --save--dev
I need to mention theinitContent
callback which is important when adding custom components inside the jqxWindow.
Because by default the content in the window is extracted there as plain HTML.
Please, take a look at this code example below:/* eslint-disabled */ import * as React from 'react'; import 'jqwidgets-scripts/jqwidgets/styles/jqx.base.css'; import JqxButton from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxbuttons'; import JqxPanel from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxpanel'; import JqxWindow from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxwindow'; class App extends React.PureComponent { myWindow = React.createRef(); events = React.createRef(); constructor(props) { super(props); this.showWindowButtonClick = this.showWindowButtonClick.bind(this); this.eventWindowClose = this.eventWindowClose.bind(this); this.eventWindowMoved = this.eventWindowMoved.bind(this); this.eventWindowOpen = this.eventWindowOpen.bind(this); this.onButtonClick = this.onButtonClick.bind(this); this.initContent = this.initContent.bind(this); } render() { return ( <div> <JqxButton onClick={this.onButtonClick} width={80}> Show </JqxButton> <button onClick={this.onButtonClick} > Outside JqxWindow Button </button> <div style={{ marginTop: 10 }}>Events Log:</div> <JqxPanel ref={this.events} style={{ border: 'none' }} width={450} height={250}> </JqxPanel> <JqxWindow ref={this.myWindow} onClose={this.eventWindowClose} onOpen={this.eventWindowOpen} onMoved={this.eventWindowMoved} width={270} height={165} maxHeight={180} maxWidth={280} minHeight={30} minWidth={250} // cancelButton={'.cancel'} // okButton={'.ok'} resizable={false} // isModal={true} modalOpacity={0.3} position={{ x: 90, y: 140 }} draggable={true} initContent={this.initContent} > <div> {/**/} Modal Window </div> <div> <div> Please click "OK", "Cancel" or the close button to close the modal window. The dialog result will be displayed in the events log. </div> <div style={{ float: "right", marginTop: 15 }}> <div> <JqxButton onClick={this.onButtonClick} className={'ok'} style={{ display: 'inline-block' }} width={80}> OK </JqxButton> <JqxButton onClick={this.onButtonClick} className={'cancel'} style={{ display: 'inline-block' }} width={80}> Cancel </JqxButton> <button className={'native-button'} > My Button </button> </div> </div> </div> </JqxWindow> </div > ); } initContent() { let nativeButton = document.getElementsByClassName("native-button")[0]; nativeButton.addEventListener("click", this.onButtonClick); } capitaliseFirstLetter(word) { return word.charAt(0).toUpperCase() + word.slice(1); }; displayEvent(event) { let eventData = 'Event: ' + this.capitaliseFirstLetter(event.type); if (event.type === 'moved') { eventData += ', X: ' + event.args.x + ', Y: ' + event.args.y; } if (event.type === 'close') { eventData += ', Dialog result: '; if (event.args.dialogResult.OK) { eventData += 'OK'; } else if (event.args.dialogResult.Cancel) { eventData += 'Cancel'; } else { eventData += 'None'; } } // this.events.current.prepend('<div style="margin-top: 5px;">' + eventData + '</div>'); }; // Event handling showWindowButtonClick() { this.myWindow.current.open(); } eventWindowClose(event) { this.displayEvent(event); } eventWindowMoved(event) { this.displayEvent(event); } eventWindowOpen(event) { // this.displayEvent(event); } onButtonClick(event) { this.events.current.prepend("<div>Some Information</div>"); } } export default App;
I hope this will help.
Best Regards,
Hristo HristovjQWidgets team
https://www.jqwidgets.comHello vmlaskin,I am sorry about the late answer.
After the simple installation of the default React project I try to add the jQWidgets scripts as follow:
npm install jqwidgets-scripts --save--dev
I need to mention theinitContent
callback which is important when adding custom components inside the jqxWindow.
Because by default the content in the window is extracted there as plain HTML.
Please, take a look at this code example below:
I hope this will help.Best Regards,
Hristo HristovjQWidgets team
https://www.jqwidgets.comthanks for respond
with all respect I can see your new way of handling events from native elements from JQXWindow content as workaround for React 17.In React 16 jqwidgets understand React way of handling events from JQXWindow content without explicitly adding listeners to elements.
jQWidgets elements such as JQXButton along with native elements form jqxwindow content work with React way of adding events as JSX element attribute (onClick). Why should it work differently in React 17I see it as jqwidgets incompatibility with breaking changes in React 17
In my view all these additional event listeners should be handled by jqwidgets under hood and make the same code working in React 16 and 17.
It would be nice if jQWidgets published some info regarding migration to React 17.BTW there is the other way to make example working without initcontent function.
Create reference for internal “native” button and add event listener to the reference element in componentDidMount().
Somehow React 17 treats ref elements differently and bubble events from JQXWindow content//in constructor private myButton: HTMLButtonElement | null =null; componentDidMount() { this.myButton!.addEventListener("click", this.onButtonClick); } // in render <button ref={(t: HTMLButtonElement)=> this.myButton=t} > My Button </button>
Hello vmlaskin,
I would like to mention that the used
initContent
callback is very important when adding inside the jqxWindow.
You could use the native React approach to achieve the mentioned scenario.
Please, take a look at this code snippet:initContent() { let buttonsContainer = document.getElementById("buttonsContainer"); let buttonSample = <button onClick={this.onButtonClick}>Click</button>; ReactDOM.render(buttonSample, buttonsContainer); }
Also, details about the
JqxWindow
tag:<JqxWindow ref={this.myWindow} onClose={this.eventWindowClose} onOpen={this.eventWindowOpen} onMoved={this.eventWindowMoved} width={270} height={165} maxHeight={180} maxWidth={280} minHeight={30} minWidth={250} // cancelButton={'.cancel'} // okButton={'.ok'} resizable={false} // isModal={true} modalOpacity={0.3} position={{ x: 90, y: 140 }} draggable={true} initContent={this.initContent} > <div> Modal Window </div> <div> <div> Please click "OK", "Cancel" or the close button to close the modal window. The dialog result will be displayed in the events log. </div> <div style={{ float: "right", marginTop: 15 }}> <div> <JqxButton onClick={this.onButtonClick} className={'ok'} style={{ display: 'inline-block' }} width={80}> OK </JqxButton> <JqxButton onClick={this.onButtonClick} className={'cancel'} style={{ display: 'inline-block' }} width={80}> Cancel </JqxButton> <div id="buttonsContainer"></div> </div> </div> </div> </JqxWindow>
Best Regards,
Hristo HristovjQWidgets team
https://www.jqwidgets.comI understand that the same things can be done differently. But it would be nice if jqwidgets preserved compatibilities when moving forward.
Handling events in jqxwindow only through initcontent function is breaking change for migration jqwidgets to React 17.
It was not required in React 16. Events from native elements worked in React 16 without need for calling initcontent.
If calling initcontent is the only way of working with native elements in jqxwindow in React 17 then it will require significant restructure and additional codding when old application migrates to React 17.
Initcontent function was in jqxwindow component for a while and was not required. My expectation is that in React 17 it should be the same. It can be used when someone need it but it should not be required the only way to work with jqxwindow.Hello vmlaskin,
I would like to mention that the
initContent
callback should be used every time when creating a custom component inside the jqxWindow.
This approach is initial for all widgets that have elements inside them – they have different “init-” callbacks.
About this case, the difference becomes from the React which treats differently the binding to events.
Please, take a look at this article.Best Regards,
Hristo HristovjQWidgets team
https://www.jqwidgets.comYes React 17 admit that there are breaking changes regarding handling events.
it is already two weeks we are discussing the jqwidgets incompatibility with React 17. your suggested approach using initcontent function is breaking change that you (jqwidgets) don’t want to admit.
JQWidgets documentation doesn’t say that Initcontent is required. And application was build and works without this function in prev React versions.
My suggestion to jqwidgets is to admit the problem with React 17 and stay on customers side. Workout React breaking changes in jqwidgets under hood for preserving customers code compatibility when migrating to React 17. At least have a plan to work on the issue and publish it in your “road map”.You can insist on your approach that practically means re-building whole application when migrating to React 17. But all this conversation is about jqwidgets reliability and relationships with customers.
Hi vmlaskin,
This demo: https://www.jqwidgets.com/jquery-widgets-demo/demos/jqxwindow/defaultfunctionality.htm?light is built 10 years ago. It shows a jqxWindow component and shows that if we need to use any component inside a window we should use initContent. In the demo case, this is jqxTabs. It has always been a requirement to use initContent for initializing components inside jqxWindow at least by how we designed the components to work. May be it is not the best design, but this is how it works.
Best regards,
Peter StoevjQWidgets Team
https://www.jqwidgets.com/Thank you
-
AuthorPosts
You must be logged in to reply to this topic.