How to use twitter bootstrap with bootstrap-sass in rails app? - ruby-on-rails

I'm quite new to this, but i cannot figure out the problem.
In twitter bootstrap i would use :
<div class="row-fluid">
<div class="span2">Column1</div>
<div class="span6">Column2</div>
</div>
And it all works fine. But i do not want to write spanX and spanY directly into my html file, rather i would like to give meaningful class names, for example:
<div class="user-container">
<div class="user-filter">First Column</div>
<div class="user-list">Second Column</div>
</div>
Given the fact, that i'm using https://github.com/thomas-mcdonald/bootstrap-sass, how should i write my scss file? I've tried the following, and it does not work (two columns are not displayed):
#import "bootstrap";
#import "bootstrap-responsive";
.user-container {
#extend .row-fluid;
}
.user-filter {
#extend .span2;
}
.user-list {
#extend .span10;
}
If i look at the generated code, it seems to me that everything should be ok:
/* line 164, ../../../../../.rvm/gems/ruby-1.9.3-p125/gems/bootstrap-sass-2.0.0/vendor/assets/stylesheets/bootstrap/_mixins.scss */
.span2, .user-filter {
width: 140px;
}
and so on.
What am i doing wrong?
UPDATE:
ok, just to be clear what is wrong - the columns are laid out as rows (one after another) rather like true columns (one next to each other), eg.:
with bootstrap: Column1 Column2
with my custom classes:
First Column
Second Column
I've inspected the elements layout in Chrome and it seems that bootstrap classes have float property, and mine - no. Looking at css source i see classes like this:
[class*="span"] {
float: left;
margin-left: 20px;
}
So in my case i think it should generate something like :
[class*="user-filter"] {
float: left;
margin-left: 20px;
}
or not?

It's your use of #extend, or rather, Sass' inability to deal with wildcard class matching, which is rather unsurprising, since it gets rather complex.
Bootstrap uses a number of what I might refer to as 'nonstandard' methods to address some classes. You've mentioned one of those in your post above - [class*="span"].
Naturally, when you use #extend x, Sass is extending the x class. Unfortunately, it (currently) has no way of knowing that a wildcard matcher also affects the output of the class. So yes, in an ideal world, [class*="span"] would also be extended to define [class*="span"], .user-filter, but Sass can't currently do that.
While extending .row-fluid is enough to include the rules nested underneath it wrt. the span classes, as per above, it won't adjust the wildcards for extended spans.
bootstrap-sass already had a mixin for fixed width columns/rows, makeRow() and makeColumn(). I've just pushed a makeFluidColumn() mixin, that, well, makes a fluid span. Your code would then become:
.user-container {
#extend .row-fluid;
}
.user-filter {
#include makeFluidColumn(2);
}
.user-list {
#include makeFluidColumn(10);
}
Unfortunately (as per usual) it's not quite so simple. Bootstrap uses this snippet to reset the margin on the first spanx class that is a child of the row.
> [class*="span"]:first-child {
margin-left: 0;
}
However, we cannot redefine this for each call of makeFluidColumn, and so we must manually set no margin-left on any element that will be the first child of a fluid row. It's also worth noting that mixing spanx classes and makeFluidColumn classes will cause the first spanx class to have its margin reset, regardless of whether it's actually the first column in the row.
Your code would therefore be
.user-container {
#extend .row-fluid;
}
.user-filter {
#include makeFluidColumn(2);
margin-left: 0; // reset margin for first-child
}
.user-list {
#include makeFluidColumn(10);
}
It's not a particularly pretty solution, but it works, and is all to do with how Bootstrap uses wildcard class matching, as you gathered in your question update. I've only just pushed this to the 2.0.2 branch, so you'll have to use Bundler with Git to install it, but I'm hoping for a release in the next couple of days.

You are right. Twitter is pushing an ani-patter here. See this article.
http://ruby.bvision.com/blog/please-stop-embedding-bootstrap-classes-in-your-html

Using boostrap-sass 2.3.2.2 gem I had to create my own mixin based on bootstrap's mixins to make CSS classes act like bootstrap .span classes.
// private mixin: add styles for bootstrap's spanX classes
#mixin _makeFluidSpan($gridColumns, $fluidGridColumnWidth, $fluidGridGutterWidth) {
#include input-block-level();
float: left;
margin-left: $fluidGridGutterWidth;
*margin-left: $fluidGridGutterWidth - (.5 / $gridRowWidth * 100px * 1%);
#include grid-fluid-span($gridColumns, $fluidGridColumnWidth, $fluidGridGutterWidth);
}
// thats what you should use
#mixin makeFluidSpan($gridColumns) {
#media (min-width: 980px) and (max-width: 1199px) {
#include _makeFluidSpan($gridColumns, $fluidGridColumnWidth, $fluidGridGutterWidth);
}
#media (min-width: 1200px) {
#include _makeFluidSpan($gridColumns, $fluidGridColumnWidth1200, $fluidGridGutterWidth1200);
}
#media (min-width: 768px) and (max-width: 979px) {
#include _makeFluidSpan($gridColumns, $fluidGridColumnWidth768, $fluidGridGutterWidth768);
}
&:first-child {
margin-left: 0;
}
#media (max-width: 767px) {
float: none;
display: block;
width: 100%;
margin-left: 0;
box-sizing: border-box;
margin-bottom: 20px;
&:last-child {
margin-bottom: 0;
}
}
}
example:
.like-span3 { // this class acts like .span3
#include makeFluidSpan(3);
}

Related

Boostrap - responsive approch with angular7 requires clarity

In my styles.scss i am importing the bootstrap variables, and did a testing it works.
#import '~bootstrap/scss/_functions.scss';
#import '~bootstrap/scss/_variables.scss';
#import '~bootstrap/scss/mixins/_breakpoints';
$grid-breakpoints: (
sm: 768px,
md: 768px,
lg: 1024px
);
$container-min-widths: (
sm: 768px,
md: 768px,
lg: 1024px
);
#import "~bootstrap/scss/bootstrap";
#include media-breakpoint-down (sm) {
body{
background: green;
}
}
#include media-breakpoint-between (md, lg) {
body{
background: blue;
}
}
#include media-breakpoint-up (lg) {
body{
background: gray;
}
}
But my question is, if i use the app.component.scss - still is it require to import all the variables again?
without import i tried, like:
#import '../../styles.scss'
#include media-breakpoint-down (sm) {
body{
background: green;
}
}
#include media-breakpoint-between (md, lg) {
body{
background: blue;
}
}
#include media-breakpoint-up (lg) {
body{
background: gray;
}
}
But got error like :
ERROR in ./src/app/app.component.scss
Module build failed (from ./node_modules/sass-loader/lib/loader.js):
#include media-breakpoint-down (sm) {
^
Media query expression must begin with '('
in D:\IBO\POC\ibo\src\app\app.component.scss (line 3, column 1)
i 「wdm」: Failed to compile.
can't we download all app specific requirement at once? or what is the correct approach?
This is how css encapsulation works in Angular, if you want to use SASS functions (like #include, #extend) in your scss with external #mixins or styles, you'll need to import these external files every time.
This is not a great practice though as it bubbles the amount of produced css in the final html page (every time you #import a file, it's whole content is copied). So a better approach would be to put some common styles in your styles.scss and use them through the whole app.
In your example I don't understand why you need to do the same in app.component.scss? Is it just for testing? You shouldn't need to - it should be enough putting common styles (like yours) in styles.scss and they should be applied to the whole application. Just make sure your style.scss is added to your angular.json file under the styles section. Something like:
"styles": [
"src/styles.scss"
]
Hope that helps.

Mat-select panel min-width

I'm trying to customize mat-select with multiple checkboxes.
for some reason the panel get wrong min-width as below:
and I don't know where its calculating this min-width.
also I tried to add panelClass and override the min-width from this class,
for example:
<mat-select #multipleSelect (selectionChange)="selectItem($event.value)" panelClass="multiple-panel" multiple>
&.multiple-panel {
min-width: 200px !important;
}
but when opening the dropdown its open with the original width (like in the pic) and after few millisecond"jump" to the custom min-width defined on the panel class.
I find the mat-select very hard to style. anybody knows how to solve this problem?
You can style your mat-select dialog box by giving a panel class (as you mentioned).
Please follow this demo : https://stackblitz.com/edit/angular-matselect-style?file=src/styles.css
to see the styled mat-select components.
Reason :
Reason for the delay is that angular for dialog-boxes, create a cdk-overlay-pane inside the cdk-overlay-container container, So in case of mat-select it provides a min-width of 180px, which is overridden by our panel class in the slight delay.
Yes, there is a slight delay in opening of dialog box and customizing its width to the specified width provided in the panel class. But the delay is acceptable in the project that i was working on. So, you can find the demo for styling the mat-select component, as i have provided 2 components and you can modify any css properties.
Try to use styles using ::ng-deep or :host >>>, if not finding any luck, please paste the styles in style.css.
Update 1 :
Tried css animations, and opacity for making smooth opening of the mat-select options.
.panel-class-applied-on-mat-select {
animation-name: opacityDelay !important;
animation-duration: 0.3s !important;
}
#keyframes opacityDelay {
0% {opacity: 0;}
25% {opacity: 0;}
50% {opacity: 0;}
75% {opacity: 0;}
100% {opacity: 1;}
}
Updated StackBlitz Demo
I used another approach.
Just added this piece of code to global style.
.mat-select-panel {
// some your code
&.ng-animating {
visibility: hidden;
}
}
You can try this solution on
DEMO StackBlitz.
Hack with opacity did not fix jumping width when select is closing.
You'll need to change viewEncapsulation to none at your component decorator.and then add following css to remove the transition effect.Have a look at viewencapsulation in angular docs https://angular.io/guide/component-styles#view-encapsulation.
#Component({
selector: 'app-selector',
templateUrl: './template.html',
styleUrls: ['./template.css'],
encapsulation: ViewEncapsulation.None
})
//CSS
.cdk-overlay-connected-position-bounding-box .cdk-overlay-pane .mat-select-panel.ng-animating {
display: none;
}
Try this way : define a panel class for your mat-select in the code and then in the global/app styling file just add:
.panel-class-name .mat-select-panel {
// add your styling here
}
It worked for me to add some component specific styling for material components.
Please go easy on me S.O. This is my first time contributing. :)
After debugging the console, and running into this issue. Solutions were not clear online. So I'm posting mine here in case someone else runs into this.
I found that there is a width permanently set for the infix class. If you unset it, and optionally add some padding to the right of the value, you'll find that will resolve the issue. Add :host for encapsulation when using ::ng-deep.
Important to Note: ::ng-deep is being permanently deprecated after Angular v14.
There is a property in the #Component() annotation called encapsulation which can be used to turn off the view encapsulation for the component instead of using ::ng-deep.
Solution for the deprecation of ::ng-deep:
#Component({
selector: 'app-selector-name',
template: `<div>Hello World!</div>`,
encapsulation: ViewEncapsulation.None,
styles: [
`
:host mat-form-field .mat-form-field-infix {
width: unset;
}
:host mat-form-field .mat-select-value {
padding-right: 0.5rem; /* 8px */
/* Alternatively, for TailwindCSS: #apply pr-2 */
}
:host .random-class {
/* some encapsulated styling... */
}
.another-random-class {
/* some non-encapsulated styling... */
}
`
]
})
Solution if you do not care about the deprecation of ::ng-deep:
:host ::ng-deep mat-form-field .mat-form-field-infix {
width: unset;
}
:host ::ng-deep mat-form-field .mat-select-value {
padding-right: 0.5rem; /* 8px */
}

Angular ui-select component : Broken after migrating to Bootstrap 4

I have a very simple ui-select component in my application like in the following examples :
http://angular-ui.github.io/ui-select/demo-basic.html
After migrating from Bootstrap 3 to Bootstrap 4. The component is still here but the results are not displayed.
What I've tried so far :
I used the console to check that they were in the code and they are.
I tried to add dropdown-item class into the results but it didn't work
I had the same issue and adding following css classes to Style.css resolved it.
/**
* ui-select.bootstrap4.shim.css
*
* Adapt `bootstrap` (v3) theme from AngularJS `ui-select`
* component to Bootstrap v4.x look and feel.
* Bootstrap v4.x look and feel
*
* Feel free to test and open issues and pull requests.
*
* #see https://angular-ui.github.io/ui-select/
*
* #project ui-select.bootstrap4.shim.css
* #version 1-20180706
* #author Francis Vagner dos Anjos Fontoura
* #copyright 2018 by the author
* #cssdoc version 1.0-pre
* #license MIT
*/
.pull-left {
float: left !important;
}
.caret {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid;
display: inline-block;
margin-left: 0;
vertical-align: middle;
width: 0;
}
.pull-right {
float: right !important;
}
.ui-select-toggle.btn {
border: 1px solid #ced4da;
}
.ui-select-choices.dropdown-menu {
display: block;
}
.ui-select-match-text {
max-height: 24px;
}
.ui-select-match.btn-default-focus {
border-radius: .25rem;
box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25);
outline: 0;
}
.ui-select-match.btn-default-focus > .ui-select-toggle {
border-color: #80bdff;
}
Reference : https://github.com/francisfontoura/angularjs.ui-select.bootstrap4.shim.css/blob/master/ui-select.bootstrap4.shim.css
Turns out in BS4, the menu is displayed only when the show class is present along with the dropdown-menu class and not displayed otherwise :
.dropdown-menu.show {
display: block;
}
To fix my issue I had to take this part from BS3 and copy it into my own app style :
.open > .dropdown-menu {
display: block;
}
I'm well aware that this is not the proper way to do it but it will do the trick until angular-ui receive a BS4 ready update.
I had the same problem and after seeing that ui-select needs a lot of work to be fixed for bootstrap 4, I wrote a small directive to replace it.
The goal was also to keep it simple and looking native in bootstrap 4.
It's available on npm.

Hide horizontal scrollbar (Angular ui-grid)

I'm trying to hide the horizontal scrollbar of a Angular ui-grid, but I can't find the right property. (Property enableScrollbars=false removes both.)
Is it possible to remove only the horizontal scrollbar?
With the latest version on Github v3.0.0-rc.16 you can disable horizontal and vertical Scrollbar separately.
Instead of
enableScrollbars = false;
use
enableHorizontalScrollbar = value;
enableVerticalScrollbar = value;
with
value = 0; /* NEVER */
value = 1; /* ALWAYS */
value = 2; /* WHEN_NEEDED */
UPDATE:
If you want to use constants instead of the integer-value, look at corresponding post:
Using ui-grid constants to disable scrollbars
UPDATE:
The option WHEN_NEEDED doesn't seem to be available at the moment.
Maybe this will be changed again, so please look for the available constants in the source code.
The Constants are defined in
https://github.com/angular-ui/ui-grid/blob/master/packages/core/src/js/constants.js
At now, the option WHEN_NEEDED doesn't seem to be available at the moment (ui-grid 3.1.1). So I have worked around by jQuery and CSS:
For simple, we just need do this:
.ui-grid .ui-grid-render-container-body .ui-grid-viewport {
overflow-x: auto !important;
/* or use: overflow-x: hide!important; */
}
To more flexible, we can use CSS class and jQuery. First, we add one more class:
.ui-grid-render-container-body .ui-grid-viewport.no-horizontal-bar {
overflow-x: hidden !important;
}
In controller, we will use this class by jQuery:
$timeout(function(){
if (!!$scope.gridOptions.data) {
$('.ui-grid-render-container-body .ui-grid-viewport').addClass("no-horizontal-bar");
}
});
To hide the blank gap when use selecting and grouping (http://i.imgur.com/veevhgQ.png), we use:
$timeout(function(){
if (!!$scope.gridOptions.data) {
/* To hide the blank gap when use selecting and grouping */
$('.ui-grid-render-container-left .ui-grid-viewport').height($('.ui-grid-render-container-left .ui-grid-viewport').height() + 17);
$('.ui-grid-render-container-body .ui-grid-viewport').addClass("no-horizontal-bar");
}
});
With 17px is height of the gap when we use selecting and grouping feature.
Demo: http://plnkr.co/edit/D9PKPkvuRy2xA6UNNXCp?p=preview
With this solution we can show the horizontal bar again easily.
If you are allowed to use flexboxes:
.ui-grid-render-container-body {
.ui-grid-header {
padding-right: 17px;
.ui-grid-header-viewport {
width: 100%;
.ui-grid-header-canvas {
width: 100%;
.ui-grid-header-cell-wrapper {
display: block;
width: 100%;
.ui-grid-header-cell-row {
display: flex;
min-width: 0;
.ui-grid-header-cell {
flex: 1 1 0;
min-width: #col-min-width;
}
}
}
}
}
}
.ui-grid-viewport {
overflow: auto !important;
display: flex;
.ui-grid-canvas {
flex: auto;
min-width: 0;
[role="row"] {
display: flex;
min-width: 0;
.ui-grid-cell {
flex: 1 1 0;
min-width: #col-min-width;
}
}
}
}
}
Where col-min-width is a minWidth that you would normally set in the gridOptions. Also you have to set the ui-grid-header's padding-right (which is 17px in this example) to the width of your browser's scrollbar with the javascript on certain events: number of rows changed, container resized etc. Scrollbar width = ui-grid-viewport's offsetWidth - clientWidth. Using a hardcoded value for scrollbar width is bad because different browsers have different (and even configurable) values for that.

How do i get multiple coordinates on a google maps static api?

I am pulling out information from the google places API I want to be able to show all the coordinates that I've pulled on one map v.s. having multiple maps on a page (as shown below). Does anyone have any suggestions?
Thank you in advance!
<%#c.each do |p|%>
<ul>
<li><%= image_tag("http://maps.googleapis.com/maps/api/staticmap?center=#{p.lat},#{p.lng}&zoom=15&size=600x300&maptype=roadmap
&markers=color:blue%7Clabel:S%7C#{p.lat},#{p.lng}&sensor=true")%></li>
<li><%=p.name%></li>
<li><%=p.rating%></li>
<li><%p.lat%></li>
<li><%p.lng%></li>
</ul>
<%end%>
If I understand you correctly you essentially need the multiple ul tags to align with each other.
Essentially you would need to give a fixed width to your ul element and apply a float. Here I have assumed that you would like three maps side-by-side.
The CSS code for it is:
* {
box-sizing:border-box;
-moz-box-sizing:border-box;
}
ul {
list-style: none;
width: 30%;
float: left;
margin: 0;
padding:1.5%;
}
ul img {
max-width:100%;
}
or if you prefer SCSS:
* {
box-sizing:border-box;
-moz-box-sizing:border-box;
}
ul {
list-style: none;
width: 30%;
float: left;
margin: 0;
padding:1.5%;
li {
img {
max-width:100%;
}
}
}
If you would like to see how this would look, check it out at http://jsfiddle.net/dheer/Ltxzj/2/
Note: If you are adding this to your rails app you may want to assign a new class to the ul tag as styling the current code may affect other design elements.
There's an answer made by Martin Bean in this thread:
How do I show multiple locations in Google Maps?
which uses the google maps javascript api. As seen in that example, you should just add Markers to the map from your coordinates (in that case he uses a bunch of coordinates that you should load from your model).

Resources