noUiSlider Handles Displaying In Incorrect Places - nouislider

I am attempting to setup a noUiSlider (version 13.1.5) from within a Polymer 3 custom element. The slider displays and technically works but the right handle is displaying where the left handle should be and the left handle is displaying outside of the container set out for the slider.
I've taken code from a Polymer 1 element that works 100% correctly but the handles aren't working in the Polymer 3 element.
The html code is as follows and has not changed between the two Polymer versions (other than the code now being in the template function for Polymer 3):
<div style="height: 50%; width: 100%">
<div id="scoreRangeSelector" style="display: flex; flex-direciton: column">
<div id="scoreRangeSelectorText">
<p>Range Selection</p>
</div>
<div id="scoreRangeSelectorSlider"></div>
<div id="scoreRangeInterval">
<p>Score Interval</p>
<input id="scoreRangeIntervalInput" on-change="_scoreRangeIntervalChanged" type="number" value="5" />
</div>
</div>
</div>
The Polymer code that sets up the slider is as follows and has not changed between the two Polymer versions (other than the retrieval of the element into the variable slider):
var slider = this.$.scoreRangeSelectorSlider;
noUiSlider.create(slider,
{
connect: true,
range:
{
'min': 0,
'max': 100
},
start: [0, 100],
step: 1,
tooltips: [true, true]
});
slider.noUiSlider.on("end", this._sliderMoved);
In the Polymer 1 element, the slider displayed correctly with it's handles, as follows:
https://www.pastiebin.com/5cd95545273b1
In the Polymer3 element, the slider displays but the right handle is displaying where the left handle should be and the left handle is displaying outside of the container, displaying under another container:
https://www.pastiebin.com/5cd9563ac618f
The handle that can be seen in the image is the handle that should be on the right hand side of the slider. The element being shown as "div.noUi-origin" is the left handle that should be on the left hand side of the slider.
The noUiSlider code seems to be adding transformations onto the handles that are pushing them off where they should be but I am unsure of what I am supposed to do to fix this.

set "direction: ltr" to "scoreRangeSelectorSlider" parent

Related

CSS selector for ionic-radio labels

I'm creating a list of radio buttons which when checked should change the color of corresponding label but it seems not to work at all using css selectors.
what am i missing here?
template-
<ion-list class="addressList">
<ion-radio-group">
<ion-item *ngFor="let address of address">
<label for="ok" >
{{address.address}}
</label>
<ion-radio id="ok" class="radio-custom" mode='ios' slot="end" value="{{address.address}}"></ion-radio>
</ion-item>
</ion-radio-group>
</ion-list>
app.scss -
:checked + label {
color: var(--ion-color-primary) !important;
}
I think the best way to figure out styling is to use chrome dev tools, click on the item in question and see what classes such element obtains during "checked" state:
Then you could build your styling rules around it, but please note that if the element is inside of a "shadow root" you need to use css variables to apply styles (since those elements' style would be incapsulated inside shadow dom)
<ion-list class="addressList">
<ion-radio-group>
<ion-item *ngFor="let address of [0,1,2,3,4,5,6,7]">
<ion-label>address #{{ address }}</ion-label>
<ion-radio mode='ios' slot="end" value="{{address}}"></ion-radio>
</ion-item>
</ion-radio-group>
</ion-list>
and css:
.item-radio-checked {
color: red;
}
You can play with many CSS vars Ionic team created from here: https://ionicframework.com/docs/api/item#css-custom-properties
These are applied at ion-item scope.

A way to render multiple root elements on VueJS with v-for directive

Right now, I'm trying to make a website that shows recent news posts which is supplied my NodeJS API.
I've tried the following:
HTML
<div id="news" class="media" v-for="item in posts">
<div>
<h4 class="media-heading">{{item.title}}</h4>
<p>{{item.msg}}</p>
</div>
</div>
JavaScript
const news = new Vue({
el: '#news',
data: {
posts: [
{title: 'My First News post', msg: 'This is your fist news!'},
{title: 'Cakes are great food', msg: 'Yummy Yummy Yummy'},
{title: 'How to learnVueJS', msg: 'Start Learning!'},
]
}
})
Apparently, the above didn't work because Vue can't render multiple root elements.
I've looked up the VueJS's official manual and couldn't come up with a solution.
After googling a while, I've understood that it was impossible to render multiple root element, however, I yet to have been able to come up with a solution.
The simplest way I've found of adding multiple root elements is to add a single <div> wrapper element and make it disappear with some CSS magic for the purposes of rendering.
For this we can use the "display: contents" CSS property. The effect is that it makes the container disappear, making the child elements children of the element the next level up in the DOM.
Therefore, in your Vue component template you can have something like this:
<template>
<div style="display: contents"> <!-- my wrapper div is rendered invisible -->
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
</div>
</template>
I can now use my component without the browser messing up formatting because the wrapping <div> root element will be ignored by the browser for display purposes:
<table>
<my-component></my-component> <!-- the wrapping div will be ignored -->
</table>
Note however, that although this should work in most browsers, you may want to check here to make sure it can handle your target browser.
You can have multiple root elements (or components) using render functions
A simple example is having a component which renders multiple <li> elements:
<template>
<li>Item</li>
<li>Item2</li>
... etc
</template>
However the above will throw an error. To solve this error the above template can be converted to:
export default {
functional: true,
render(createElement) {
return [
createElement('li', 'Item'),
createElement('li', 'Item2'),
]
}
}
But again as you probably noticed this can get very tedious if for example you want to display 50 li items. So, eventually, to dynamically display elements you can do:
export default {
functional: true,
props: ['listItems'], //this is an array of `<li>` names (e.g. ['Item', 'Item2'])
render(createElement, { props }) {
return props.listItems.map(name => {
return createElement('li', name)
})
}
}
INFO in those examples i have used the property functional: true but it is not required of course to use "render functions". Please consider learning more about functional componentshere
Define a custom directive:
Vue.directive('fragments', {
inserted: function(el) {
const children = Array.from(el.children)
const parent = el.parentElement
children.forEach((item) => { parent.appendChild(item) })
parent.removeChild(el)
}
});
then you can use it in root element of a component
<div v-fragments>
<tr v-for="post in posts">...</tr>
</div>
The root element will not be rendered in DOM, which is especially effective when rendering table.
Vue requires that there be a single root node. However, try changing your html to this:
<div id="news" >
<div class="media" v-for="item in posts">
<h4 class="media-heading">{{item.title}}</h4>
<p>{{item.msg}}</p>
</div>
</div>
This change allows for a single root node id="news" and yet still allows for rendering the lists of recent posts.
In Vue 3, this is supported as you were trying:
In 3.x, components now can have multiple root nodes! However, this does require developers to explicitly define where attributes should be distributed.
<!-- Layout.vue -->
<template>
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
</template>
Multiple root elements are not supported by Vue (which caused by your v-for directive, beacause it may render more than 1 elements). And is also very simple to solve, just wrap your HTML into another Element will do.
For example:
<div id="app">
<!-- your HTML code -->
</div>
and the js:
var app = new Vue({
el: '#app', // it must be a single root!
// ...
})

reactjs unrecognized tag attributes

TLDR:
Is there a way to force-append an attribute to a react tag?
.
The full story:
I'm using reactjs and i've run into a problem with SVG and foreignObjects.
I wanted to center text in an SVG image so i figured the easiest approach would be to use a div in a foreign object.
It works fine on chrome, but in firefox the text isn't displayed.
On closer inspection, it appears that my
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"
requiredExtensions="http://www.w3.org/1999/xhtml"
xmlns="http://www.w3.org/2000/svg"
Isn't coming through to the browser.
I've read the reactjs docs which suggested putting the prefix
data-
in, but the prefix stays in the browser.
I also tried to set the required features using the style={...}, but then this was inside the style string and not inserted as a tag attribute.
React Code:
import React, {Component,PropTypes} from 'react';
export default class myComponent extends Component {
render() {
return (<svg width = {this.props.width}
height = {this.props.height}>
<foreignObject x = {0} y = {0}
width = {this.props.width}>
<div> <p> {this.props.title} </p> </div > </foreignObject>
</svg>)
}
PARTIAL ANSWER:
I haven't been able to get text in a foreignObject to work with react in firefox, but i did work out how to set 'arbitary' tag attributes.
For each of the react components i assigned refs, i.e.:
<div style={divStyle} ref="d2">
<p style={{wordWrap: 'normal', textAlign: 'left', margin: 'auto', position: 'relative'}} key="p2">
{Math.round(this.props.kW)} W
</p>
</div>
Then in componentdidmount:
componentDidMount() {
this.refs.svg1.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
this.refs.svg1.setAttribute('version', '1.2');
this.refs.fo1.setAttribute('requiredExtensions', 'http://example.com/SVGExtensions/EmbeddedXHTML');
this.refs.d1.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
this.refs.fo2.setAttribute('requiredExtensions', 'http://example.com/SVGExtensions/EmbeddedXHTML');
this.refs.d2.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
this.refs.fo3.setAttribute('requiredExtensions', 'http://example.com/SVGExtensions/EmbeddedXHTML');
this.refs.d3.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
this.refs.fo4.setAttribute('requiredExtensions', 'http://example.com/SVGExtensions/EmbeddedXHTML');
this.refs.d4.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
this.refs.fo5.setAttribute('requiredExtensions', 'http://example.com/SVGExtensions/EmbeddedXHTML');
this.refs.d5.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
this.refs.fo6.setAttribute('requiredExtensions', 'http://example.com/SVGExtensions/EmbeddedXHTML');
this.refs.d6.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
}
This actually broke the foreign object in BOTH chrome and firefox!!
I think the issue is that i'm going by
https://www.w3.org/TR/SVG/extend.html
and they have:
<body xmlns="http://www.w3.org/1999/xhtml">
<p>Here is a paragraph that requires word wrap</p>
</body>
But since you can't use the <body> tag inside a react component, this doesn't get rendered.
I will manually edit the code in firefox and see if the inclusion of <body> in the foreign object fixes this issue.
I think the only option I have is to layer a second SVG component over the top of the first then use setInnerHTMLDangerously to write all of the foreign objects inside. Such a filthy hack!!

Reveal.js presentation full screen from JHipster

I am trying to show a reveal.js presentation full screen from a JHipster single page app. The reveal.js example below works fine inside JHipster, it's just not full screen. It can be made full screen by creating a second page, but given JHipster's design as a single page app things get messy with grunt and the production profile. I've also tried hiding the app menu bar and footer div elements but the reveal presentation still has padding around it. Ideally a full-screen view can configured.
Simple Reveal slide
<div ng-cloak>
<div class="reveal">
<div class="slides">
<section data-background="#faebd7">
<h1>FULL SCREEN SLIDE</h1>
</section>
</div>
</div>
</div>
A second page is the way to go and below is a way to by-pass optimizations made by JHipster's production build.
JHipster's production build only optimizes files under src/main/webapp/scripts and src/main/webapp/assets directories. So, put your presentation files including revealjs under another folder (e.g. src/main/webapp/slides) and use a simple link from your app to load the presentation.
This is what is done for swagger-ui under src/main/webapp/swagger-ui
I solved the problem while keeping it a single page app. Previously I tried hiding elements of the page that prevented full-screen, but padding on the main div container was preventing full screen. The solution was to create a second ui-view div designed for full screen and hide all other div elements.
Solution:
1. Add "hidewhenfullscreen" class to the elements to hide.
2. Use javascript to show/hide elements
3. Add a second fullpage ui-view designed for full screen
4. Reference the fullpage ui-view from the controller
index.html
<div ng-show="{{ENV === 'dev'}}" class="development hidewhenfullscreen" ng-cloak=""></div>
<div ui-view="navbar" ng-cloak="" class="hidewhenfullscreen"></div>
<div class="container hidewhenfullscreen">
<div class="well" ui-view="content"></div>
<div class="footer">
<p translate="footer">This is your footer</p>
</div>
</div>
JavaScript to show/hide elements
<script>
hide(document.querySelectorAll('.hidewhenfullscreen'));
function hide (elements) {
elements = elements.length ? elements : [elements];
for (var index = 0; index < elements.length; index++) {
elements[index].style.display = 'none';
}
}
function show (elements) {
elements = elements.length ? elements : [elements];
for (var index = 0; index < elements.length; index++) {
elements[index].style.display = 'block';
}
}
</script>
JavaScript controller
.state('show', {
parent: '',
url: '/show/{presentationName}',
data: {
authorities: [], // none, wide open
pageTitle: 'page title'
},
views: {
'fullpage#': {
templateUrl: 'scripts/show/show.html',
controller: 'ShowController'
}
}
})
The page has a single small "Home" href that calls the show function. This way the user can go back and forth between the full-screen Reveal presentation and the standard jHipster view.
show.html
<div ng-show="{{ENV === 'dev'}}" class="development"></div>
<div class="miniMenu" id="miniMenu" ng-cloak="">
Home
</div>
<div class="reveal">
<div class="slides">
<section data-background={{getBackgroundURI($index)}} ng-repeat="slide in slides track by $index">
<div ng-bind-html="getContent($index)"></div>
</section>
</div>
</div>
For completeness, creating a second page can work but I don't think it is worth the added complexity. A two-page solution worked fine in the development profile, but the production profile had issues with caching shared css files, js files and fonts. With time and energy, I am sure the proper grunt configuration can be made to work, although the idea seems to counter the single page design concept. While in Rome, do as the Romans do.

Trying to create onclick event in node js grid using KOGrid

I would like to have a nice interactive grid view in an HTML page. I am using nodejs, express, twitterbootstrap, knockoutjs, for my technology stack. I am trying to use KOGrid to display various data points with some nice built in column sorting and other grid functionality.
My issue is trying to fire an event when a button is clicked in a row. And pass to that event, some of the various data fields from that specific row. So in KOGrid specifics, I am using cellTemplates and I need to call some function in the onclick event, but pass that function some KOGRID data bounded values. So, in my input element I would have
data-bind="onclick: [Name of my function]( [name of some data bounded variable], [name of some other data bounded variable])
Can someone show me how to do this?
Here is a sample of my code...the input/onclick in the CBTemplate is where I am having issues.
CBTEMPLATE:
<script type="text/html" id="actionTemplate">
<div data-bind="kgCell: $cell">
<input type="checkbox" value="1" class="checkbox" checked="checked" data-bind="onclick: 'MyOnClickFunction( siteId(), status() )'"/>
</div>
</script>
DIV TAG:
<div data-bind="koGrid: { data: offer.siteCounts,
columnDefs: [ { field: 'templateField0', displayName: 'Site', cellTemplate: 'siteTemplate', width: 150},
{ field: 'status', displayName: 'Current Status', cellClass: 'site', cellTemplate: 'statusTemplate', width: 115},
{ field: 'details', displayName: 'Details', width: 175},
{ field: 'actionField0', displayName: 'Action', cellTemplate: 'cbTemplate', width: 200}],
autogenerateColumns: false,
displaySelectionCheckbox: false,
isMultiSelect: false }">
</div>
The click event binding should look like this with KO:
data-bind="click: function(data,event) { MyOnClickFunction(siteId(), status()) }"
Here is a working JSFiddle where you can play with it.
Some sidenotes:
In my sample I have used the $root binding context property to access the sample function: $root.offer.MyOnClickFunction. You will need to adjust this depending on which level you have defined the MyOnClickFunction on your viewmodels.
You need to return true from the click binding handler if you do want to let the default click action proceed (e.g checking the checkbox etc.)

Resources