Extends paper input in Polymer 3 - javascript

im trying extends the paper-input component from Polymer 3 like documentation says but i cant.
https://polymer-library.polymer-project.org/3.0/docs/devguide/dom-template#inherit
In the next example you can try using the snippet. The problem is the import of paper-input hasnt PaperInputElement export so i cant import. You must to see here : https://unpkg.com/#polymer/polymer/polymer-element.js?module
Could you help me?
<script type='module'>
import 'https://unpkg.com/#polymer/paper-input#3.0.1/paper-input.js?module';
import {PolymerElement, html} from 'https://unpkg.com/#polymer/polymer/polymer-element.js?module';
class DmInput extends PaperInputElement {
static get template() {
return html`
<style>
</style>
<p>hi</p>
<p>${super.template}</p>
`;
}
}
window.customElements.define('dm-input', DmInput);
</script>
<dm-input></dm-input>

I believe you're attempting to import the wrong file here, Paper-input is just a ui component that uses the PaperInputBehavior. Try replacing PaperInputElement in this case with the behavior as all functions, properties and events that the input element uses come from it.
class DmInput extends PaperInputBehavior {
static get template() {
return html`
<style>
</style>
<p>hi</p>
<p>${super.template}</p>
`;
}
}

Related

Why a ts-class-based vue-component's static method, which is declared in .vue, can only work in a .vue's script block?

Why a ts-class-based vue-component's static method, which is declared in .vue, can only work in a .vue's script block?
steps to reproduce
use vue-cli3 to init a typescript project and add shims-vue.d.ts
declare module "*.vue" {
import Vue from "vue";
export default Vue;
}
add Comp.vue file in your project as below
// Comp.vue
<template>
<div></div>
</template>
<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator";
#Component
export default class Comp extends Vue {
mounted() {
}
created(){
}
static notWorkFunc(){
//anything
}
}
export function anotherNotWorkFunc(){
//anything
}
</script>
add test.ts and test.vue in your project with specific code as below
test.vue
<script lang="ts">
import ComP,{anotherNotWorkFun} from "./Comp.vue";
ComP.notWorkFunc()
anotherNotWorkFun()
</script>
test.ts
import ComP,{anotherNotWorkFun} from "./Comp.vue";
ComP.notWorkFunc()
anotherNotWorkFun()
As you can see
in .ts not work
in .vue work
I don't know the reason...
The repo is https://github.com/WilkinWendy/vue-ts-problem.
The democode is in ./src/demo
FYI
I think the typescript class components in .vue files actually get compiled to a Vue options object and that is how they are exported.
What we do in our project, is in the .vue file we just have the template and at the bottom we have external reference to a code-behind file.
Example:
<!-- Comp.vue -->
<template>
<div></div>
</template>
<script lang="ts" src="./Comp.ts"></script>
<style lang="scss" src="./Comp.scss"></style>
Then we do the following:
// Comp.ts
import { Component } from "vue-property-decorator";
export const SOME_CONST = "SomeValue";
#Component
export class Comp extends Vue{
public static method(): boolean {
return true;
}
}
export default Comp;
this seems to work for us and actually the performance of VSCode/Vetur/TypeScript is much better this way. In addition, when the UX folks work on the CSS/HTML they don't have to touch the .ts file.

How can I pass hrefs to my method in Vue js with `#click`?

I am following the accepted answer of this question: Hide links from Google via JavaScript
I want to pass the href to my method linkAction(), how can I achieve this with an #click?
This is what I have so far
<template>
<span
href="https://www.w3schools.com/" <-- some url
#click="linkAction(this)"
>
Link to W3 Schools
</span>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
#Component
export default class MainContent extends Vue {
linkAction(e: any): any {
console.log(e);
}
}
</script>
I am getting on my console: null. Would appreciate some help. Thanks!
In the template you need to change #click="linkAction(this)" to #click="linkAction($event)".
And in method linkAction you do something like this:
linkAction(e) {
console.log(e.target.getAttribute('href'));
}
this is not accessible from template
but you can simply use ref attribute and then use this.$refs to get element
<template>
<span
ref="link"
href="https://www.w3schools.com/" <-- some url
#click="linkAction"
>
Link to W3 Schools
</span>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
#Component
export default class MainContent extends Vue {
linkAction(): any {
console.log(this.$refs.link);
}
}
</script>
One option is to make link as part of your component's data, and then use it in the linkAction method.
<template>
<span
:href="link"
#click="linkAction">
Link to W3 Schools
</span>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
#Component
export default class MainContent extends Vue {
data(): any {
return {
link: 'https://www.w3schools.com/'
}
},
linkAction(): any {
console.log(this.link);
}
}
</script>

How do I add javascript code into reactJS file? [duplicate]

This question already has answers here:
Changing style of a button on click
(6 answers)
Closed 3 years ago.
I am very new to reactjs and javascript in general, and I'm trying to figure out how to get this simple js code to work in my reactjs file. I want the text to turn red onClick.
I have tried: Creating an external js file and importing it using Helmet to insert a tag
import React, { Component } from 'react';
import './about.css';
import logo from './S54 Logo 2.svg';
import { Helmet } from "react-helmet";
import aboutJS from './about';
export default class About extends Component {
render() {
return (
<div id="about-page">
<Helmet>
<script>
{'aboutJS'};
</script>
</Helmet>
<img id="about-page-logo-img" src={logo} />
<h2 id="mission-statement" onclick="myFunction()">
Catalog the World's Underrepresented Art so everyone can share in the enjoyable experience
</h2>
</div>
)
}
}
this was the js file
export function myFunction() {
document.getElementById("mission-statement").style.color = "red";
}
Ive also tried adding that js code straight into the script tag, instead of importing the file but that didn't work.
I tried putting a tag for that external js file I created into the of my index.html file, and calling the function in my reactjs file.
Nothing is working. Where and how should I add this code?
In JSX, props use this syntax: propName={...} with strings being an exception, where you can do propName="...".
So you should just be able to do onClick={myFunction}
Edit: you might have to do onClick={myFunction.bind(this)} to get your desired effect.
Edit: fixed Camel Case
Zelmi, React uses JSX, which means Javascript XML. You can write JS directly into the component like this:
import React, { Component } from 'react';
import './about.css';
import logo from './S54 Logo 2.svg';
import aboutJS from './about';
export default class About extends Component {
myFunction() {
document.getElementById("mission-statement").style.color = "red";
}
render() {
return (
<div id="about-page">
<Helmet>
<script>
{'aboutJS'};
</script>
</Helmet>
<img id="about-page-logo-img" src={logo} />
<h2 id="mission-statement" onclick="myFunction()">
Catalog the World's Underrepresented Art so everyone can share in the enjoyable experience
</h2>
</div>
)
}
}
And thus call the myFunction from anywhere in the page.
You also need to understand how React and the VirtualDOM work, start by reading the docs.
React does not work with the standard html onclick attribute but rather with the React prop onClick, which takes in a function as well, but you need to show React XML that you are calling your JS code by opening a {} code scope like so:
<div id="about-page">
<Helmet>
<script>
{'aboutJS'};
</script>
</Helmet>
<img id="about-page-logo-img" src={logo} />
<h2 id="mission-statement" onClick={this.myFunction}>
Catalog the World's Underrepresented Art so everyone can share in the enjoyable experience
</h2>
</div>
EDIT
You also unfortunately need to bind your function when using React Class component, in the constructor method:
constructor(props) {
super(props);
// This binding is necessary to make `this` work in the callback
this.myFunction = this.myFunction.bind(this);
}
Part of the point of React is to abstract away the DOM so you don't have to do things like getElementById and all that.
A simple way to accomplish what you want to do would be something like this:
export default class About extends Component {
constructor(props) {
super(props);
this.state = {
color: "black"
}
}
myFunction = () => {
this.setState({color: "red"});
}
render() {
return (
<div id="about-page">
<img id="about-page-logo-img" src={logo} />
<h2 onClick={this.myFunction} style={{color: this.state.color}}>
Catalog the World's Underrepresented Art so everyone can share in the enjoyable experience
</h2>
</div>
)
}
}
Note that if your setup doesn't allow arrow functions in class properties, you may have to bind this to the function like so:
constructor(props) {
super(props);
this.state = {
color: "black"
}
this.myFunction = this.myFunction.bind(this);
}
Zelmi, You can import { myFunction } from 'path/to/your/jsfile.js' which allows you to use myFunction any where in your JS file where your component lives.
Also, use onClick instead of onclick, wrap your function with Carely Braces {} instead of Quotes ""
import React, { Component } from 'react';
import './about.css';
import logo from './S54 Logo 2.svg';
import { myFunction } from 'path/to/your/jsfile.js'; //HERE
import { Helmet } from "react-helmet";
import aboutJS from './about';
export default class About extends Component {
render() {
return (
<div id="about-page">
<Helmet>
<script>
{'aboutJS'};
</script>
</Helmet>
<img id="about-page-logo-img" src={logo} />
<h2 id="mission-statement" onClick={myFunction}>
Catalog the World's Underrepresented Art so everyone can share in the enjoyable experience
</h2>
</div>
)
}
}

Converting a dynamic HTML page to React/JSX

As a simple example, suppose I had these two files:
example.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8" />
<title>Button example</title>
<script type="text/javascript" src="ButtonHandler.js"></script>
</head>
<body id="body" onload="init()">
<button onclick=buttonHandler.writeToConsole()>Button</button>
<script>
function init() {
buttonHandler = new ButtonHandler();
}
</script>
</body>
</html>
ButtonHandler.js
function ButtonHandler() {
};
ButtonHandler.prototype.writeToConsole = function () {
console.log('Writing');
}
This simply prints to the console whenever the button is clicked.
Ignore that the ButtonHandler's constructor is empty, and that I could just easily call 'console.log' in the onclick directly. This is a simplified version of an issue I'm having, with several classes.
My question is, how would I go about translating this to React/JSX, ideally without modifying the Javascript files (in this case, just ButtonHandler.js). Ideally this means no exporting/importing, I'd like to do it how the HTML file does it - it just links to the script in the <\head>.
The closest I have is something like this:
convert.jsx
import * as React from 'react';
export default class Entry extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
buttonHandler = new ButtonHandler();
}
render() {
return (
<div>
<title>Button example</title>
<button onclick="buttonHandler.writeToConsole()">Button</button>
</div>
)
}
}
But I get the error that ButtonHandler is undefined. I followed this stackexchange answer and placed
<script type="text/javascript" src="[rest of path...]/ButtonHandler.js"></script>
in the public/index head, and I added the 'window.ButtonHandler' in componentDidMount(), but I still get the error that it's undefined.
Am I doing something wrong, and if not, what other approach can I take?
edit: When I put ButtonHandler.js in the public folder with index, and I console log the window, I see it appear as a function of window, like the stackexchange answer describes. This doesn't happen when I have it in another folder, though. Same error however.
edit 2: Seems the only solution is to put ButtonHandler.js in the public folder and then call it in the constructor like the selected answer says. Then add a
<button onClick={() => this.buttonHandler.writeToConsole()}>Button</button>
to call it.
In create react app, you should be able to add any js files to your public folder for use in your project. You just need to reference the files in your script like:
<script type="text/javascript" src="%PUBLIC_URL%/ButtonHandler.js"></script>
That will make sure that it looks in the public folder when building.
The only problem with that is that the files won't be minified in the bundle.
Edit
You will have to reference the global variable inside your component as well.
/* global ButtonHandler */
import * as React from 'react';
export default class Entry extends React.Component {
constructor(props) {
super(props);
this.buttonHandler = new ButtonHandler();
}
render() {
return (
<div>
<title>Button example</title>
<button onclick={this.buttonHandler.writeToConsole}>Button</button>
</div>
)
}
}
You'll want to import that ButtonHandler js code. If it's not something you've written yourself, the easiest thing to do would be to see if it already exists as a React package. If it's your own file, then you'll want to export the functions in ButtonHandler.js, import ButtonHandler in your React component, then you'll have access to them in the component.
ButtonHandler.js
export function writeToConsole() {
console.log('Writing');
}
convert.jsx
import React, { Component } from 'react';
import { writeToConsole } from './ButtonHandler';
export default class Entry extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<title>Button example</title>
<button onclick={this.writeToConsole}>Button</button>
</div>
)
}
}

Next.js custom class on body using _document.js

I'm using the example here
https://github.com/zeit/next.js#custom-document
and I want to change the custom_class on the body tag
I have tried passing props on calling components but nothing works. I want to add a 'dark' class based on some condition but I have no idea how to change this.
EDIT:
I'm not sure this is possible. After getting help from the nextjs slack channel I was told
"Pages get rendered client side with next/link
And body is not touched after server side rendering"
I'm going to try and wrap things in another tag that I generate and try and change that.
The cleanest solution I found is not declarative, but it works well:
import Head from "next/head"
class HeadElement extends React.Component {
componentDidMount() {
const {bodyClass} = this.props
document.querySelector("body").classList.add(bodyClass || "light")
}
render() {
return <Head>
{/* Whatever other stuff you're using in Head */}
</Head>
}
}
export default HeadElement
With this Head component you would pass in "dark" or "light" (following the question's example for light/dark themes) as the bodyClass prop from the page.
As of current Next (10) and React (17) versions, If you'd like to change the body class from a page, you can can do it like this:
// only example: maybe you'll want some logic before,
// and maybe pass a variable to classList.add()
useEffect( () => { document.querySelector("body").classList.add("home") } );
Please note that useEffect is a Hook, so it can be used only in modern function components, not class ones.
The useEffect Hook can be used instead of the 'old' componentDidMount LifeCycle.
https://reactjs.org/docs/hooks-effect.html
https://reactjs.org/docs/hooks-overview.html
https://reactjs.org/docs/components-and-props.html
The only way to directly access the body tag on Next js is via the _document.js file but this file is rendered server side as stated in the Documentation.
The work around I suggest is to access the body tag from the component directly. Example:
const handleClick = (e) => {
document.querySelector('body').classList.toggle('dark')
}
<div onClick={handleClick}>Toggle</div>
The solution I came up with for my situation where I don't need a lot of unique body classes was to create a component called BodyClass.js and import that component into my Layout.js component.
BodyClass.js
import { Component } from 'react';
class BodyClass extends Component {
componentDidMount() {
if (window.location.pathname == '/') {
this.setBodyClass('home');
} else if (window.location.pathname == '/locations') {
this.setBodyClass('locations');
}
}
setBodyClass(className) {
// remove other classes
document.body.className ='';
// assign new class
document.body.classList.add(className);
}
render() {
return null;
}
}
export default BodyClass;
Layout.js
import Header from './Header';
import Footer from './Footer';
import BodyClass from '../BodyClass';
const Layout = ({ children }) => {
return (
<React.Fragment>
<BodyClass />
<Header />
{children}
<Footer />
</React.Fragment>
)
}
export default Layout;
Unfortunately, next/head does not allow specifying body class like React Helmet does:
<Helmet>
<body className="foo"/>
</Helmet>
Luckily, you can use this.props.__NEXT_DATA__.props.pageProps inside _document.js to get access to the page props and use them to to set the class on the <body> element:
import Document, { Html, Head, Main, NextScript } from 'next/document';
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
return { ...initialProps };
}
render() {
const pageProps = this.props?.__NEXT_DATA__?.props?.pageProps;
console.log('pageProps => ', pageProps);
return (
<Html>
<Head />
<body className={pageProps.bodyClassName}>
<Main />
<NextScript />
</body>
</Html>
);
}
}
More info here.
Directly, it's not possible. But with another way, you can use framework like tailwind and insert the class directly in your css.
Here an example using tailwind:
.dark {
background-color: black;
color: white;
}
body {
#apply dark
}
It's not exactly the answer you are looking for, but I was able to accomplish the same thing functionally by passing a prop through the component which then updates a class on a top-level element that wraps everything in my app and sits just under the . This way each page can have it's own unique class and operates the same way I'd use a body class.
Here is where I pass the prop through
<Layout page_title={meta_title} page_desc={meta_desc} main_class={'contact_page'}>
And here is where I use it in the Layout component:
<main className={props.main_class}>
<Header page_title={props.page_title} page_desc={props.page_desc} />
{props.children}
<Footer />
</main>
This is my CSS only solution:
(I first looked at https://stackoverflow.com/a/66358460/729221 but that felt too complex for changing a bit of styling.)
(This uses Tailwind CSS, but does not need to.)
index.css:
body:has(#__next .set-bg-indigo-50-on-body) {
#apply bg-indigo-50;
}
layout.tsx:
//…
return (
<div className="set-bg-indigo-50-on-body">{children}</div>
)
This will work, as long as that div is a direct parent of <div id="__next">. Otherwise you need to update the css :has-rule.

Categories

Resources