I have installed lit as well as fontawesome as npm packages.
I also use the Vaadin Router package for some routing.
Now I want to insert some icons on my own elements.
While the icons are replaced correctely in the index html they are not in all the seperate elements.
For replacing the icons I use the dom.i2svg method of the js-api from fontawesome. If I understood correctly this should also be used and activated automatically by using the npm package of frontawesome.
The files of interest are the following:
index.html
<body>
<navigation-element></navigation-element>
<i class="fab fa-linkedin"></i>
<main>
<div id="outlet"></div>
</main>
<footer-element></footer-element>
<script src="./vendor/webcomponents-loader.js"></script>
</body>
index.js
import { dom, library } from '#fortawesome/fontawesome-svg-core'
import { fas } from '#fortawesome/free-solid-svg-icons'
import { fab } from '#fortawesome/free-brands-svg-icons'
const outlet = document.getElementById('outlet');
const router = new Router(outlet);
router.setRoutes([
{ path: '/', component: 'my-element' },
]);
library.add(fas, fab);
dom.i2svg();
my-element.js
import { dom } from '#fortawesome/fontawesome-svg-core';
class MyElement extends LitElement {
static styles = css `
:host {
display: block;
}
`;
connectedCallback() {
super.connectedCallback();
dom.i2svg(); // does not work in here
}
render() {
return html `
<i class="fas fa-kiwi-bird"></i>
<i class="fab fa-linkedin"></i>
<div>
<p> text </p>
<p> text </p>
</div>
`;
}
}
customElements.define('my-element', MyElement);
In the index.js I added my icons to the library and in the index.html the the i element is correctly replaced. But for the my-element nothing happens. The library is filled with the icons but no elements are replaced. I tried to call the dom.i2svg() and/or dom.watch(params) inside the connecedCallback function aswell as in the constructor.
I also tried various other things/functions like importing css.
Someone else had a similar issue which could be solved on github, but this solution does not work for me.
Has someone an idea why? What did I wrong, is it maybe the router or is the api just broken?
Your component extends from LitElement which means it has a shadow DOM that shields its internal HTML from external CSS. You can:
Extend from View instead of LitElement to avoid using shadow DOM (if your project is based on Vaadin's Hilla starter)
Override createRenderRoot() { return this; } in your LitElement to not use shadow DOM. This will disable shadow DOM for whole component.
Include fontawesome styles in your component template with <style>
Use slot for content intended to be in light DOM. This is better approach when you want to partially protect the implementation, e.g. your component is a layout with dynamic content.
Related
Basically I'm trying to make a navbar for a personal website application in which the navbar references content (About/Skills, etc.) all on single page (route). When making the navbar, I can easily reference markup with ids/classes BUT I would have to put all the html in one file.
I noticed that if I were to separate each content into its own react file (About.jsx, Skills.jsx, etc.) and import them, there didn't seem to be a way for me to reference the react component's markup.
I also noticed with react router, this wasn't feasible because each component would be on a separate route (which I don't want) rather than on a single route.
This is my current navbar file below; How exactly Can I import and reference the markup of the separate components?
import React from 'react';
import "../Styles/NavBar.scss";
import About from "./About.jsx"; (Not used)
import Skills from "./Skills.jsx"; (Not Used)
import Projects from "./Projects.jsx"; (Not used)
const NavBar = () => (
<div class="MainDivWrapper">
<div class="NavBarDiv">
<h1 class="NavBarH1">NavBar</h1>
<br/>
<nav>
About
Skills
Projects
</nav>
{/* <div id="AboutDiv">
<h1>About Me</h1>
<span>Just some text</span>
</div>
<div id="SkillsDiv">
<h1>Skills</h1>
<span>Just some text</span>
</div>
<div id="ProjectssDiv">
<h1>Projects</h1>
<span>Just some text</span>
</div> */}
</div>
<hr class="HeaderDivider"/>
</div>
)
You reference a JSX import like that:
/* Component have to start with a capital letter. file name can be anything (usually is the same as component) */
import MyComponent from "./MyComponent"
export default function MyApp() {
return (
<div>
/* other html/components here */
<MyComponent /> // selfing close tag
/* or */
<MyComponent> // with `children`
some content
</MyComponent>
</div>
)
}
Here is a codesandbox implementation of your code: https://codesandbox.io/s/stack-reactjs-navbar-is-it-possible-to-reference-a-different-components-markup-64oic?file=/src/App.js
I am trying to implement a project like:
https://codepen.io/andytran/pen/GpyKLM
As you can see there is javascript that is needed for the page to function. I am trying to build a Next/React component that implements this code:
import React, { Component } from 'react';
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
class Auth extends Component {
render() {
return (
<div className="App">
<Header></Header>
<div className="container mrgnbtm">
<div className="row">
<div>
hello
</div>
</div>
</div>
</div>
);
}
}
export default Auth;
Where would I put the javascript in the above example? Also, how would I call code from a scss file?
What you do is anti-pattern, instead of importing bootstrap from a CDN you can use reactstrap package.
for element listeners, must pass those to each element that you want, like onClick:
<div id="button" onClick={() => alert("button clicked!")} ....
and for using SCSS in your next app, first you have to install the sass package:
npm install sass --save
then reload the dev server and import SCSS file in component, e.g:
import styles from '../../styles/Home.module.scss'
I started a project using Express and Handlebars and then was encouraged to look at Vue.js. I am still at the stage of reading the docs but so far can't understand how to have layouts, partials and sections in Vue.js. I think a partial would be a component, but I'm lost how to have a layout with partials and sections that I can inject content into.
This is what I do using npm express-handlebars in a file called baselayout.hbs:
<!doctype html>
<html lang="en">
<head>
{{> global/headcode }} <!-- partial view with code for the head tag. it has stuff like favicon links --->
{{{_sections.pagemeta}}} <!-- page specific metadata injected here. this would be meta keywords description etc for a page/view --->
</head>
<body>
<div>
{{> global/siteheader }} <!--- partial view for the site's header --->
<div id="base-Container">
<main id="base-Content" role="main">
{{{ body }}} <!--- a page's main body content goes here --->
</main>
</div>
</div>
{{> sitefooter }}
{{{_sections.pagescripts}}} <!-- section for page-specific scripts injected here --->
</body>
</html>
How could I setup something like the above in Vue.js that would also work with server-side rendering? I just need a base layout with header/footer components included but also sections into which page-specific content can go.
For SSR, you should look at Nuxt.js, Vapper, or one of the other SSR Vue frameworks.
That said, yes, you would use components for everything. Generally, you would have one component for your main layout, then one for each view, then individual components for each partial/section that you would then import into your views and/or main layout. So, for example, based on the above code:
Your main app layout:
// AppLayout.vue
<template>
<div id="app-layout">
<site-header />
<router-view />
<site-footer />
</div>
</template>
<script>
import SiteHeader from './components/global/SiteHeader.vue'
import SiteFooter from './components/global/SiteFooter.vue'
export default {
name: 'AppLayout',
components: {
SiteHeader,
SiteFooter
},
meta: {
// metatags and other head content can be modified using vue-meta or similar
}
}
</script>
Example 'partial' component:
// BaseContainer.vue
<template>
<main id="base-container" role="main">
<h1 class="title">{{ content.title }}</h1>
<img :src="image" alt="" />
<base-content v-html="content.body" />
</main>
</template>
<script>
import BaseContent from './components/content/BaseContent.vue'
export default {
name: 'BaseContainer',
components: {
BaseContent
},
props: {
content: {
type: Object,
default() {
return {}
}
},
image: {
type: String,
default: ''
}
}
}
</script>
Example view component:
// MyView.vue
<template>
<div id="my-view">
<base-container :content="content" :image="image" />
</div>
</template>
<script>
import BaseContainer from './components/BaseContainer.vue'
import content from './data/myContent.json'
import image from './assets/myImage.jpg'
export default {
name: 'MyView',
components: {
BaseContainer
},
data() {
return {
content,
image
}
}
}
</script>
You would then use vue-router to specify which view component to load based on the current URL.
You probably need to use components and slots within your components.
Yes you need to create a component for each of your partials. Each component would have a template.
Then you will have a main component that will put all of this together. Using the more granular components you already have (your partials).
Now if the template structure (html for each component) is coming from the server then you can prob use slots https://v2.vuejs.org/v2/guide/components-slots.html which is a way VueJs allow components to receive custom markup when instantiating the components (see the example in the docs)
For the general layout and UI components of your app you may want to look at https://element.eleme.io/#/en-US/component/layout which is a nice alternative to the more popular Vuetify.
I appreciate your time and help. I spent hours trying to figure this out can't seem to get to the bottom of it.
I have this react component:
import styles from './style.scss';
class ButtonComponent extends React.Component {
render() {
return (
<div className={styles.bunny}>
hello world
</div>
);
}
}
and scss file:
.bunny {
display: block;
margin-top:50px;
margin-bottom:55px;
background-color: blue;
}
When I load up my html, the div has no classname when I expect it to be <div class="bunny">
When I put the class name in the react component literally like this:
<div className="bunny">
then I can see the className in the browser.
What am I doing wrong?
Thank you so much in advance.
Firstly, you need to guarantee it's defined with: console.log(styles)
Im' not sure you import style.scss correctly.
You need to import your scss like...
import './styles.scss';
Webpack will take care of bundling your styles so you can add the className as a string on your component.
<div className="bunny">Hello World</div>
What fixed this for me was to change the name of my scss file from style.scss to style.module.scss
For me it's because I use commonjs's require to load an es module.
A React.js app gives the warning
Warning: validateDOMNesting(...): <a> cannot appear as a descendant of <a>.
See Element > a > ... > a.
What does that mean? How can you prevent it? Are nested links illegal in HTML, HTML5 or React.js?
That means:
<a href="1">
</a>
Is invalid HTML. Browsers will recognize this and turn this into:
React warns you about this because the browser's fix will make the actual DOM different from the virtual DOM, leading to strange bugs when React goes to update stuff.
Heed React's warning and don't nest <a> tags.
I was also getting this warning for my Navigation,
I was using react-bootstrap to render React Router Link in NavItem.
Warning: validateDOMNesting `<a>` cannot appear as a descendant of `<a>`.
in a (created by Link)
Fix: Add componentClass attribute to render NavItem as <span> tag instead of <a> tag (You can use any other tag name here)
My code was
<Nav pullRight>
<NavItem>
<Link to="/responses">Responses</Link>
</NavItem>
</nav>
After fix
<Nav pullRight>
<NavItem componentClass='span'>
<Link to="/responses">Responses</Link>
</NavItem>
</nav>
This also messes up styling, to fix it add the following CSS
.navbar-nav span[role=button] {
padding: 15px;
display: inline-block;
line-height: 20px;
}
What does that mean?
It means that:
<a href="http://example.com">
<span>
<a href="http://example.net">
...
</a>
</span>
</a>
and
<a href="http://example.com">
<a href="http://example.net">
...
</a>
</a>
and similar constructs are not allowed. They don't make sense anyway.
How can you prevent it?
This isn't something that happens without someone writing code that tries to do it.
You need to find that code and change it.
Are nested links illegal in HTML, HTML5 or React.js?
They are illegal in all versions of HTML. The first DTD for HTML was published as part of HTML 2. It says:
<!ELEMENT A - - %A.content -(A)>
The last part describes what content is allowed inside the element. The -(A) part of that means "Except for A elements".
HTML 5 is just the 2014 update to HTML. HTML 5.1 came out last year (2016). HTML 5.2 is under development.
React.js is a JavaScript library that generates an HTML DOM. The results are still (sort of) HTML.
You can use a function instead of a tag:
import React from 'react';
import PropTypes from 'prop-types';
import { Link, withRouter } from 'react-router';
class SomeClass extends React.Component {
constructor(props, context) {
super(props, context);
this.redirect = this.redirect.bind(this);
}
redirect(target) {
this.context.router.push("/path");
}
render() {
return (
<div>
<p onClick={this.redirect}>Link</p>
</div>
);
}
}
SomeClass.contextTypes = {
router: PropTypes.object
};
export default SomeClass;
Be careful to use a context.
I'm using a context for routing only.
class SomeClass extends React.Component {
constructor(props, context) {
super(props, context);
this.redirect = this.redirect.bind(this);
}
}