Using flexbox with angular 2 components - javascript

I want to update visual side(grid, colors) of my angular 2 application. Old layout was build with bootstrap 4, which I don't really need anymore. I decided to go for plain css3, and build grid with flexbox. I made a preview of this grid on codepen.
However implementation in project is hard and I am now stuck. Let's consider an example:
import {Component} from 'angular2/angular2';
#Component({
selector: 'some-component',
template: `
<aside class="col-4 main-aside"></aside>
<section class="main-section center"></section>
`
})
export class SomeComponent { }
If I bootstrap this component within, for example .container I may get this result:
<body>
<!-- .container is flex parent -->
<div class="container">
<some-component>
<!-- .main-aside and .main-section should be flex children -->
<aside class="main-aside"></aside>
<section class="main-section center"></section>
</some-component>
</div>
</body>
As you can see the flex chain parent -> child is broken because of component "selector" between them. I menaged to fix this by adding styles: display: flex; width: 100%; to component selector from chrome dev tools, however I don't know how to make this work from code perspective nor is it the best way to do so.
I would really appreciate any help, because I have no idea how to fix this with the exception of not using flexbox.
I am using angular 2.0.0-alpha.44
And yes, I am aware of angular's alpha state.

I fixed this issue by adding styles to component. For example:
:host {
display: flex;
}
:host {} was the key.

:host selector solves the problem but you end using it very often in many components.
I used instead the following global CSS:
.row > * {
display: flex;
flex-basis: 100%;
}

The angular team released their own flex-layout package, so you don't need to write it by your self anylonger:
https://github.com/angular/flex-layout

Related

Compile Vue.js to static HTML

I would like to be able to take a Vue.js component and compile it to static html (ideally at runtime). I do not need any javascript but I do need styles. I'm looking for a library where I could run something along the lines of this:
SomeNestedComponent.vue
<template>
<div class="world">
World!
</div>
</template>
<style lang="scss">
.world {
background: blue;
}
const vueComponent = `
<template>
<div class="hello">Hello!</div>
<SomeNextedComponent />
</template>
<style lang="scss">
.hello {
background: red;
}
</style>
`
const staticHtml = compileVueComponent(vueComponent)
Output:
<body>
<div style="background: red;">Hello!</div>
<div style="background: blue;">World!</div>
</body>
You will not get any benefits from using Vue here especially for email templates, quite the opposite (need back and forth without a lot of plus value).
If you need to create some dynamic views with backend data, you'll better be using EJS, Jinja, pug or any other backend templating language. You could achieve dynamic rendering, looping on lists, bring your CSS and pretty much everything needed for an email template.
This video could also be somehow helpful I guess (didn't watched it myself): https://www.vuemastery.com/conferences/vueconf-us-2021/html-email-with-vue.js/

Targeting Pure elements in next.js with CSS modules

I'm porting an app from React to Next and I keep getting an error with my css: "ul" is not pure (pure selectors must contain at least one local class or id).
I'm using css modules and am not sure what the workaround is to keep everything in the css module.
for example:
index.js
<div className={styles.container}>
<ul>
<li>Person One</li>
</ul>
</div>
index.module.css
.container{
background-color: pink;
}
ul{
list-style-type: none; //this throws an error
}
If you don't want to use classes as mentioned #Zeeshan's answer, you cannot use the module-based CSS. You will need to use a global stylesheet to target pure elements as selectors. They cannot be component-scoped.
Further, you can only import a global stylesheet in one place (_app.tsx/_app.jsx/_app.js), or you'll receive an error (explained here).
You may break your styles out across many stylesheets, but they all have to be global, so there's probably little benefit from doing so.
To quote directly from this Next.js GitHub discussion forum:
You are receiving this error because you are using html tags directly instead of classnames or ids in a file extension that is probably [filename].module.(css | scss | sass)
File extensions with *.module.(css | scss | sass) are css modules and they can only target elements using classnames or ids and not using tag names. Although this is possible in other frameworks like create-react-app, it is not possible in next-js.
My suggestion is using these html selector css in a separate file that doesn't contain the '.module' in it.
Example: [filename].(css | scss | sass) --> styles.scss
And instead of importing like this
import styles from './styles.module.scss';
import like this
import './styles.scss';
This is actually extremely simple.
You can add a container class to the top element (just like you did), and then use combinators ( ,+,>, etc.) to target pure elements as you wish.
For example:
index.js:
<div className={styles.container}>
<ul>
<li>Person One</li>
</ul>
</div>
index.module.css:
.container {
background-color: pink;
}
.container ul {
list-style-type: none;
}
Try giving a className or id to ul tag and then write your styles accordingly.
for example:
index.js
<div className={styles.container}>
<ul className={styles.container__list}>
<li>Person One</li>
</ul>
</div>
index.module.css
.container {
background-color: pink;
}
.container__list{
list-style-type: none;
}

How to style a nested component from its parent component in Vuejs?

I am going to create a layout like 'header sidebar main-content sidebar footer ' with flexbox by Vuejs.
I created separate .vue files for each part of the layout , I mean something like a sidebar.vue and a header.vue and so on ....
And I am going use them in App.vue file like :
<template>
<div id="app">
<app-header ></app-header>
<app-sidebar></app-sidebar>
<app-content></app-content>
<app-sidebar></app-sidebar>
<app-footer></app-footer>
</div>
</template>
<script>
import header from "./components/header";
import sidebar from "./components/sidebar";
import content from "./components/content";
import footer from "./components/footer";
export default {
components: {
"app-header": header,
"app-sidebar": sidebar,
"app-content": content,
"app-footer": footer
}
};
</script>
<style lang="scss">
body {
margin: 0;
padding: 0;
}
#app {
border: 3px solid red;
min-height: 100vh;
display: flex;
flex-wrap: wrap;
> * {
border: 1px solid black;
}
}
the main problem is I can not select these custom nested components from App.vue file to style them. for example i can not use app-header{} like other normal tags in html and css to select it and style it within style tags inside of App.vue file . is there anyway to solve it ?
NOTE : I know I can assign a class to each of these nested components and then select them to use with css class selector .
I would handle this by creating a property in each of the child components (maybe HeaderClass, BodyClass, and so on). That way, any component that consumes these child components can pass whatever classes they desire and style them accordingly.
<app-header :headerclass="parent-header-class"> </app-header>
Inside of your child component, you can use these properties and v-bind the class inside the HTML, as shown in the example below:
<template>
<div :class=`${headerClass} internal-class-example button`> </div>
</template>
Note: This does not allow you to use any scoped parent CSS to pass to the child. The classes you pass down must be global. Otherwise, the child component will not know what it is.

In Vue.js, is there a way to keep component templates out of JavaScript strings?

I just worked through the Guide on Vue.js's website, and I have a bad feeling about templates for components. It seems strange to me that they are specified in strings; sure, maybe this works for very short templates, but once you get to multiline templates, you need to start escaping your new lines and it just feels wrong to have html in javascript strings to begin with. Not to mention that syntax highlighting or any other nice IDE features are useless with HTML in JS strings.
Two alternatives that are detailed in the docs are using inline templates, or X-templates, but both of these options are discouraged.
The only other alternative seems to be Single File Components, which seems like a good option, but they are in the Advanced section and in the docs, it is said that for small and medium sized apps, simply using Vue.component should be enough. Furthermore, Single File Components look like they're more difficult to integrate into a project, requiring tapping into the project's build system (the docs talk about Webpack and Browserify).
So I'm confused. Do I just need to accept that my component code is going to look as messy as this example, pulled straight from the docs?
Vue.component('currency-input', {
template: '\
<span>\
$\
<input\
ref="input"\
v-bind:value="value"\
v-on:input="updateValue($event.target.value)"\
>\
</span>\
',
......
Given that you are starting a new project, you can use vue-hackernews-2.0 as boilerplate, where you see lot of components already coded with webpack integration for both dev and prod env. This is also developed by core vue team and recommended in official docs.
You can see there are different files for each component and one component looks like following having clear separation of HTML, JS and CSS part:
<template>
<li v-if="comment" class="comment">
<div class="by">
<router-link :to="'/user/' + comment.by">{{ comment.by }}</router-link>
{{ comment.time | timeAgo }} ago
</div>
<div class="text" v-html="comment.text"></div>
<div class="toggle" :class="{ open }" v-if="comment.kids && comment.kids.length">
<a #click="open = !open">{{
open
? '[-]'
: '[+] ' + pluralize(comment.kids.length) + ' collapsed'
}}</a>
</div>
<ul class="comment-children" v-show="open">
<comment v-for="id in comment.kids" :id="id"></comment>
</ul>
</li>
</template>
<script>
export default {
name: 'comment',
props: ['id'],
data () {
return {
open: true
}
},
computed: {
comment () {
return this.$store.state.items[this.id]
}
},
methods: {
pluralize: n => n + (n === 1 ? ' reply' : ' replies')
}
}
</script>
<style lang="stylus">
.comment-children
.comment-children
margin-left 1.5em
.comment
border-top 1px solid #eee
position relative
.by, .text, .toggle
font-size .9em
margin 1em 0
.by
color #999
a
color #999
text-decoration underline
.text
overflow-wrap break-word
a:hover
color #ff6600
pre
white-space pre-wrap
.toggle
background-color #fffbf2
padding .3em .5em
border-radius 4px
a
color #999
cursor pointer
&.open
padding 0
background-color transparent
margin-bottom -0.5em
</style>
This uses webpack for build and adds working config as well which I myself am using in production without any issue.
You can use <template>...</template> or <script type="text/x-template">...</script>, and specify the selector in template attribute for that.
<template id="myComponent">
<div>
<h1>Hello!</h1>
<p><slot></slot></p>
</div>
</template>
Vue.component('myComponent', {
template: '#myComponent'
})
Simple working example here: http://codepen.io/anon/pen/dNWrZG?editors=1010
Also, the build process of single file components is not that difficult. You can check the webpack-simple template: https://github.com/vuejs-templates/webpack-simple, the vue-loader will do everything for you.
Once you feel comfortable with webpack, you can take a look at the full webpack template: https://github.com/vuejs-templates/webpack
From my experiences, if the template is very short, use inline mode is OK. If not, x-template also allows you to get rid of escaping line breaks. I don't see why you think these approaches are discouraged. Can you provide more information?
However, if you insist to embed long template inline, you can still do that without escaping. The answer is ES6 template literals - string wrapped within ``:
template: `
<span>
$
<input
ref="input"
v-bind:value="value"
v-on:input="updateValue($event.target.value)"
>
</span>
`,
On the other hand, I really think vue-cli is a great tool. Webpack is something worth learning.
This is not really a direct answer (It's editor Specific) but i just thought i should share, but if you're using Visual Studio Code as your editor, Then you can keep your templates as part of your component and still get Syntax highlighting.
Thanks to this awesome extension
angular-2-inline
It was Originally meant for Angular 2, but it works for all ES6 Template strings (Provided the key of Template String is "template").
Single File components are the Recommended way, but they can become a burden when you're not building a Full-fledged SPA and you're just using Vue to enhance some HTML templates Here and there, and you don't want to get Involved with Webpack.
Don't believe it? I'm currently using it.
Thanks to #danidee answer I was able to track an Atom extension to properly do syntax highlighting for "backticked" HTML strings. However as he indicates it will only work when the template is declared inside the very component definition (and I want to separate template in another .js file). So I did this and it's a more ellegant solution, I think:
COMPONENT DEFINITION
/* template definition */
import { csFooterView } from './csfooter-view.js?v6';
/* component definition */
const csfooter = {
name: 'csfooter',
props: ['projectName'],
data: function() {
return {
copyrightCompany: 'CSDev'
}
},
template: csFooterView.template
};
/* exports */
export { csfooter };
TEMPLATE DEFINITION
/**
* VUE Footer Component
* Template
*/
/* template definition */
const csFooterView = {
template: `
<footer class="footer bg-warning p-4 m-auto">
<p>{{ copyrightCompany }} (c) 2020 - {{ projectName }}</p>
</footer>
`
};
export { csFooterView }
ATOM SCREENSHOT WITH HTML SYNTAX HIGHLIGHTING IN THE .JS FILE
Link to Atom extension

Angular 2.0 and ng-style

I am building an Angular 2.0 component and I want to control it's style dynamically (using ng-style). After a quick view on Angular 2's docs i tried this:
<div class="theme-preview" ng-style="{'font-size': fontSize}">
{{fontSize}}
</div>
And saw that the size is actually printed inside the div but did not affected the style. fontSize is one of component's property bindings', meaning the component gets it from its parent like this:
<my-component [font-size]="size" />
While inside the component I have:
#Component({
selector: 'XXX',
properties: ['fontSize']
})
Am I missing something here?
Update
People still reach this answer, so I've updated the plnkr to beta.1. Two things have changed so far
NgStyle is no longer necessary to be explicitly added in directives property. It's part of the common directives that are added by default.
The syntax has changed, now it must be camel case.
Example
#Component({
selector : 'my-cmp',
template : `
<div class="theme-preview" [ngStyle]="{'font-size': fontSize+'px'}">
{{fontSize}}
</div>`
})
class MyCmp {
#Input('font-size') fontSize;
}
#Component({
selector: 'my-app',
directives: [MyCmp],
template: `
<my-cmp [font-size]="100"></my-cmp>
`
})
See this plnkr (Updated to beta.1)
For specific style, you can also use this:
<div class="theme-preview" [style.font-size]="fontSize+'px'">
Something like this is actually working on latest version of angular right now 4, the syntax actually changed, please notice the [ngStyle]
.color-box {
width: 10px;
height: 10px;
display: inline-block;
}
<div class="color-box" [ngStyle]="{'background-color': your.model.object.color_code}"></div>

Categories

Resources