React Material ui input field to custom - reactjs

Hi does anyone have any idea to make the input field behave like this example?
https://www.westpac.com.au/personal-banking/home-loans/calculator/mortgage-calculator/
we should not allow user to delete 0 and when user type should replace 0 with the value, and when we delete all the value, the cursor will always stays at the end of the first digit.

The below code should work the way you want it.
function theFunction(e) {
if (e.value <= 0) return e.value = 0
if (e.value[0] == 0) return e.value = e.value.substring(1)
}
body{
width: 100vw;
height: 100vh;
}
.custom-input {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
background-color: rgb(42, 46, 66);
color: rgb(249, 249, 251);
padding: 18px;
font-size: 48px;
height: 84px;
margin-bottom: 18px;
border-color: rgb(171, 175, 177);
}
<body>
<input type="number" class="custom-input" id="custom-input" oninput="theFunction(this)" value="800">
</body>

I think you can use the if condition in your handleChange function, for example :
...
var result = 0;
if(input <= 0 || input == ''){
result = 0;
} else {
result = event.target.value;
}
this.setState({
inputValue: result
})
...
Hope this will help you :)

Related

D3 background image unwanted hiding

After hours of work, trying to add a background to my svg i finally did it, but unfortunately if you go to resolution width= 767 and bellow the background image disappear. I really have no idea why is happening.
Here is the code i am using:
const width = 555
const height = 555
const canvas = d3.select(element)
.append('div')
.classed(css.svgContainer, true)
.append('svg')
.attr('preserveAspectRatio', 'xMinYMin meet')
.attr('viewBox', `0 0 ${width} ${height}`)
.attr('xmlns', 'http://www.w3.org/2000/svg')
.classed(css['svg-content-responsive'], true)
for (let i = 1; i < svg.length; i++) {
if (svg[i].type === 'path') {
const id = setItemId(i)
defs.append('svg:pattern')
.attr('id', id)
.attr('width', '275')
.attr('height', '281')
.attr('patternUnits', 'userSpaceOnUse')
.attr('patternTransform', 'matrix(1,0,0,1,0,0) translate(251.5,142.3)')
.append('svg:image')
.attr('xlink:href', imageSrc)
.attr('width', '275')
.attr('height', '281')
.attr('x', 0)
.attr('y', 0)
}
}
// Here is the css which makes the svg responsive
.svgContainer {
display: inline-block;
position: relative;
width: 100%;
padding-bottom: 100%; /* aspect ratio */
vertical-align: top;
overflow: hidden;
}
.svg-content-responsive {
display: inline-block;
position: absolute;
left: 0;
}

SCSS for loop: mix variable with index

In the following situation, I would like to combine variables with the loop index (in SCSS):
Predefined variables
$item-width-1: 400px;
$item-height-1: 340px;
$item-spacing-1: 40px;
$item-width-2: 200px;
$item-height-2: 440px;
$item-spacing-2: 100px;
$item-width-3: 300px;
$item-height-3: 240px;
$item-spacing-3: 60px;
For loop:
#for $i from 2 through 3 {
&:nth-child(#{$i}) {
.image { width: $item-width-#{$i}; height: $item-height-#{$i}; bottom: $item-spacing-#{$i}; }
.content { transform: translate(calc(#{$item-width-#{$i}} + 40px), 0); bottom: $item-spacing-#{$i}; }
.line { height: 108px + $item-spacing-#{$i}; left: $item-width-#{$i} / 2; }
&.active { width: $item-width-#{$i} + ($content-width + 80px); }
}
}
But it shows the following error:
Any ideas on how I could fix this?
Thank you in advance!

AngularJS - NVDA screen reader not finding names of child elements

Apologies for the bare-bones HTML here...
I've got some AngularJS components that are rendering this HTML for a multiselectable dropdown:
<ul role="listbox">
<li>
<div ng-attr-id="ui-select-choices-row-{{ $select.generatedId }}-{{$index}}" class="ui-select-choices-row ng-scope" ng-class="{active: $select.isActive(this), disabled: $select.isDisabled(this)}" role="option" ng-repeat="opt in $select.items" ng-if="$select.open" ng-click="$select.select(opt,$select.skipFocusser,$event)" tabindex="0" id="ui-select-choices-row-0-1" style="">
<a href="" class="ui-select-choices-row-inner" uis-transclude-append="">
<span ng-class="{'strikethrough' : rendererInactive(opt)}" title="ALBANY" aria-label="ALBANY" class="ng-binding ng-scope">ALBANY</span>
</a>
</div>
(a hundred or so more options in similar divs)
</li>
</ul>
What we need is for screen reading software to speak aloud each option as it's highlighted via arrow key navigation. As it is now, NVDA says "blank" when keying through the list. If, in the directive we're using to create this HTML, I add role="presentation" to the <ul>, then NVDA will recite the entire list of options as soon as the dropdown opens, but not individually for each arrow key keystroke (and after hitting Escape to make it stop talking, keying through the options says "blank" again).
I keep thinking that the listbox and option roles are in the correct places, but is something else in the structure preventing the screen reader from finding the values correctly?
This answer got quite long, the first 3 points are most likely the problem, the rest are other considerations / observations
There are a few things that are likely to cause this issue, although without seeing the generated HTML rather than the Angular Source there could be others.
Most likely culprit is that your anchors are not valid. You cannot have a blank href (href="") for it to be valid. Looking at your source code could you not remove this and adjust your CSS or change it to a <div>?
Second most likely culprit is that role="option" should be on the direct children on role="listbox". Move it to your <li>s and make them selectable with tabindex="-1" (see below point on tabindex="0") instead. (in fact why not simply remove the surrounding <div> and apply all of your angular directives to the <li> directly).
Third most likely culprit is the fact that aria-label is not needed and may in fact be interfering, a screen reader will read the text within your <span> without this. Golden rule - do not use aria unless you can't portray the information another way.
You also need to add aria-selected="true" (or false) to each <li role="option"> to indicate whether an item is selected or not.
Also you should add aria-multiselectable="true" to the <ul> to indicate it is a multi select.
While you are at it, remove the title attribute, it doesn't add anything useful here.
aria-activedescendant="id" should be used to indicate which item is currently focused.
Be careful with tabindex="0" - I can't see if this is applied to everything but really it should be tabindex="-1" and you programatically manage focus as otherwise users could tab to items that they aren't meant to. tabindex="0" should be on the main <ul>.
Due to the complex nature of multi-selects you would be much better using a group of checkboxes as they provide a lot of the functionality for free, but that is just a suggestion.
The following example I found on codepen.io covers 95% of everything if you use a checkbox instead and would be a good base for you to pick apart and adapt to your needs, as you can see checkboxes make life a lot easier as all the selected not selected functionality is built in.
(function($){
'use strict';
const DataStatePropertyName = 'multiselect';
const EventNamespace = '.multiselect';
const PluginName = 'MultiSelect';
var old = $.fn[PluginName];
$.fn[PluginName] = plugin;
$.fn[PluginName].Constructor = MultiSelect;
$.fn[PluginName].noConflict = function () {
$.fn[PluginName] = old;
return this;
};
// Defaults
$.fn[PluginName].defaults = {
};
// Static members
$.fn[PluginName].EventNamespace = function () {
return EventNamespace.replace(/^\./ig, '');
};
$.fn[PluginName].GetNamespacedEvents = function (eventsArray) {
return getNamespacedEvents(eventsArray);
};
function getNamespacedEvents(eventsArray) {
var event;
var namespacedEvents = "";
while (event = eventsArray.shift()) {
namespacedEvents += event + EventNamespace + " ";
}
return namespacedEvents.replace(/\s+$/g, '');
}
function plugin(option) {
this.each(function () {
var $target = $(this);
var multiSelect = $target.data(DataStatePropertyName);
var options = (typeof option === typeof {} && option) || {};
if (!multiSelect) {
$target.data(DataStatePropertyName, multiSelect = new MultiSelect(this, options));
}
if (typeof option === typeof "") {
if (!(option in multiSelect)) {
throw "MultiSelect does not contain a method named '" + option + "'";
}
return multiSelect[option]();
}
});
}
function MultiSelect(element, options) {
this.$element = $(element);
this.options = $.extend({}, $.fn[PluginName].defaults, options);
this.destroyFns = [];
this.$toggle = this.$element.children('.toggle');
this.$toggle.attr('id', this.$element.attr('id') + 'multi-select-label');
this.$backdrop = null;
this.$allToggle = null;
init.apply(this);
}
MultiSelect.prototype.open = open;
MultiSelect.prototype.close = close;
function init() {
this.$element
.addClass('multi-select')
.attr('tabindex', 0);
initAria.apply(this);
initEvents.apply(this);
updateLabel.apply(this);
injectToggleAll.apply(this);
this.destroyFns.push(function() {
return '|'
});
}
function injectToggleAll() {
if(this.$allToggle && !this.$allToggle.parent()) {
this.$allToggle = null;
}
this.$allToggle = $("<li><label><input type='checkbox'/>(all)</label><li>");
this.$element
.children('ul:first')
.prepend(this.$allToggle);
}
function initAria() {
this.$element
.attr('role', 'combobox')
.attr('aria-multiselect', true)
.attr('aria-expanded', false)
.attr('aria-haspopup', false)
.attr('aria-labeledby', this.$element.attr("aria-labeledby") + " " + this.$toggle.attr('id'));
this.$toggle
.attr('aria-label', '');
}
function initEvents() {
var that = this;
this.$element
.on(getNamespacedEvents(['click']), function($event) {
if($event.target !== that.$toggle[0] && !that.$toggle.has($event.target).length) {
return;
}
if($(this).hasClass('in')) {
that.close();
} else {
that.open();
}
})
.on(getNamespacedEvents(['keydown']), function($event) {
var next = false;
switch($event.keyCode) {
case 13:
if($(this).hasClass('in')) {
that.close();
} else {
that.open();
}
break;
case 9:
if($event.target !== that.$element[0] ) {
$event.preventDefault();
}
case 27:
that.close();
break;
case 40:
next = true;
case 38:
var $items = $(this)
.children("ul:first")
.find(":input, button, a");
var foundAt = $.inArray(document.activeElement, $items);
if(next && ++foundAt === $items.length) {
foundAt = 0;
} else if(!next && --foundAt < 0) {
foundAt = $items.length - 1;
}
$($items[foundAt])
.trigger('focus');
}
})
.on(getNamespacedEvents(['focus']), 'a, button, :input', function() {
$(this)
.parents('li:last')
.addClass('focused');
})
.on(getNamespacedEvents(['blur']), 'a, button, :input', function() {
$(this)
.parents('li:last')
.removeClass('focused');
})
.on(getNamespacedEvents(['change']), ':checkbox', function() {
if(that.$allToggle && $(this).is(that.$allToggle.find(':checkbox'))) {
var allChecked = that.$allToggle
.find(':checkbox')
.prop("checked");
that.$element
.find(':checkbox')
.not(that.$allToggle.find(":checkbox"))
.each(function(){
$(this).prop("checked", allChecked);
$(this)
.parents('li:last')
.toggleClass('selected', $(this).prop('checked'));
});
updateLabel.apply(that);
return;
}
$(this)
.parents('li:last')
.toggleClass('selected', $(this).prop('checked'));
var checkboxes = that.$element
.find(":checkbox")
.not(that.$allToggle.find(":checkbox"))
.filter(":checked");
that.$allToggle.find(":checkbox").prop("checked", checkboxes.length === checkboxes.end().length);
updateLabel.apply(that);
})
.on(getNamespacedEvents(['mouseover']), 'ul', function() {
$(this)
.children(".focused")
.removeClass("focused");
});
}
function updateLabel() {
var pluralize = function(wordSingular, count) {
if(count !== 1) {
switch(true) {
case /y$/.test(wordSingular):
wordSingular = wordSingular.replace(/y$/, "ies");
default:
wordSingular = wordSingular + "s";
}
}
return wordSingular;
}
var $checkboxes = this.$element
.find('ul :checkbox');
var allCount = $checkboxes.length;
var checkedCount = $checkboxes.filter(":checked").length
var label = checkedCount + " " + pluralize("item", checkedCount) + " selected";
this.$toggle
.children("label")
.text(checkedCount ? (checkedCount === allCount ? '(all)' : label) : 'Select a value');
this.$element
.children('ul')
.attr("aria-label", label + " of " + allCount + " " + pluralize("item", allCount));
}
function ensureFocus() {
this.$element
.children("ul:first")
.find(":input, button, a")
.first()
.trigger('focus')
.end()
.end()
.find(":checked")
.first()
.trigger('focus');
}
function addBackdrop() {
if(this.$backdrop) {
return;
}
var that = this;
this.$backdrop = $("<div class='multi-select-backdrop'/>");
this.$element.append(this.$backdrop);
this.$backdrop
.on('click', function() {
$(this)
.off('click')
.remove();
that.$backdrop = null;
that.close();
});
}
function open() {
if(this.$element.hasClass('in')) {
return;
}
this.$element
.addClass('in');
this.$element
.attr('aria-expanded', true)
.attr('aria-haspopup', true);
addBackdrop.apply(this);
//ensureFocus.apply(this);
}
function close() {
this.$element
.removeClass('in')
.trigger('focus');
this.$element
.attr('aria-expanded', false)
.attr('aria-haspopup', false);
if(this.$backdrop) {
this.$backdrop.trigger('click');
}
}
})(jQuery);
$(document).ready(function(){
$('#multi-select-plugin')
.MultiSelect();
});
* {
box-sizing: border-box;
}
.multi-select, .multi-select-plugin {
display: inline-block;
position: relative;
}
.multi-select > span, .multi-select-plugin > span {
border: none;
background: none;
position: relative;
padding: .25em .5em;
padding-right: 1.5em;
display: block;
border: solid 1px #000;
cursor: default;
}
.multi-select > span > .chevron, .multi-select-plugin > span > .chevron {
display: inline-block;
transform: rotate(-90deg) scale(1, 2) translate(-50%, 0);
font-weight: bold;
font-size: .75em;
position: absolute;
top: .2em;
right: .75em;
}
.multi-select > ul, .multi-select-plugin > ul {
position: absolute;
list-style: none;
padding: 0;
margin: 0;
left: 0;
top: 100%;
min-width: 100%;
z-index: 1000;
background: #fff;
border: 1px solid rgba(0, 0, 0, 0.15);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
display: none;
max-height: 320px;
overflow-x: hidden;
overflow-y: auto;
}
.multi-select > ul > li, .multi-select-plugin > ul > li {
white-space: nowrap;
}
.multi-select > ul > li.selected > label, .multi-select-plugin > ul > li.selected > label {
background-color: LightBlue;
}
.multi-select > ul > li.focused > label, .multi-select-plugin > ul > li.focused > label {
background-color: DodgerBlue;
}
.multi-select > ul > li > label, .multi-select-plugin > ul > li > label {
padding: .25em .5em;
display: block;
}
.multi-select > ul > li > label:focus, .multi-select > ul > li > label:hover, .multi-select-plugin > ul > li > label:focus, .multi-select-plugin > ul > li > label:hover {
background-color: DodgerBlue;
}
.multi-select.in > ul, .multi-select-plugin.in > ul {
display: block;
}
.multi-select-backdrop, .multi-select-plugin-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 900;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<label id="multi-select-plugin-label" style="display:block;">Multi Select</label>
<div id="multi-select-plugin" aria-labeledby="multi-select-plugin-label">
<span class="toggle">
<label>Select a value</label>
<span class="chevron"><</span>
</span>
<ul>
<li>
<label>
<input type="checkbox" name="selected" value="0"/>
Item 1
</label>
</li>
<li>
<label>
<input type="checkbox" name="selected" value="1"/>
Item 2
</label>
</li>
<li>
<label>
<input type="checkbox" name="selected" value="2"/>
Item 3
</label>
</li>
<li>
<label>
<input type="checkbox" name="selected" value="3"/>
Item 4
</label>
</li>
</ul>
</div>
Also you will see that gov.uk uses a checkbox pattern (within the organisation filter on the left on the linked page) for their multi-selects (with a filter - something you may consider with 100 different options as they have highlighted some key concerns in this article).
As you can see (and I wasn't finished) there is a lot to consider.
Hope I haven't scared you too much and the first few points solve the issue you originally asked about!

How to group rows on range when cell value is number in ag-grid-react?

I am trying to group rows according to range of numbers like < 50, 50-69,70-100, 100+ but rows are grouped according to value in a cell in each row.
I have a custom filter for the column on which i am enabling rowGroup, I have a cell renderer which renders the cell style according to the value. the cell renderer return a value or html string which is rendered in grid cell. when you enable row group the same cell renderer return the the ranges i.e <50 , 50-69, 70-100, 100+, But group count is not according to these range instead it is grouped on value of the cell.
field Definition:
{
headerName:"PH Index",
field: "botScore",
width: 120,
cellStyle: { textAlign : 'center', padding: '0px 0px' },
cellRenderer: this.scoreRenderer,
filter: "scoreFilter",
enableRowGroup: true,
enablePivot: true,
menuTabs : ['filterMenuTab', 'generalMenuTab', 'columnsMenuTab'],
},`
CellRenderer:
scoreRenderer(params){
let progress;
if(typeof(params.value)== "number"){
progress = Math.round((params.value/150)*100);
if(params.value===0){
return '<div style="font-size: 13px; font-weight: 600; background: #ffffff color: #000000">'+params.value+'</div>';
}
else if(params.value<50 && params.value>0){
return '<div style="font-size: 13px; font-weight: 600; background: linear-gradient(to right, red '+progress+'%, transparent '+progress+'%); color: #000">'+params.value+'</div>';
}
else if(params.value>49 && params.value<70){
return '<div style="font-size: 13px; font-weight: 600; background: linear-gradient(to right, orange '+progress+'%, transparent '+progress+'%); color: '+(progress > 55? "#fff":"#000")+'">'+params.value+'</div>';
}
else if(params.value>69 && params.value<100){
return '<div style="font-size: 13px; font-weight: 600; background: linear-gradient(to right, #53bd9c '+progress+'%, transparent '+progress+'%); color: '+(progress > 55? "#fff":"#000")+'">'+params.value+'</div>';
}
else if(params.value>100){
return '<div style="background: linear-gradient(to right, green '+progress+'%, transparent '+progress+'%); font-size: 13px; font-weight: 600; color: #fff">'+params.value+'</div>';
}
}
else{
let value = parseFloat(params.value);
if(value<50){
return '< 50';
}
else if(value>49 && value<70){
return '50 - 69';
}
else if(value>69 && value<101){
return '70 - 100';
}
else if(value>100)
return '100+';
}
}
AgGridReact component use:
`
<AgGridReact
enableFilter = { true }
enableSorting = { true }
enableColResize = { true }
onGridReady = { this.onGridReady.bind(this) }
onFilterChanged = {this.filterChanged.bind(this)}
frameworkComponents = {this.state.frameworkComponents}
columnDefs = { this.state.columnDefs }
rowData = { this.state.rowDefs }
/>`
Ex.
row1 - value 11
row2 - value 30
row3 - value 55
row4 - value 110
row5 - value 135
So if you group these rows according to range mentioned above you should get this
<50(2),
50-100(1),
100+(2)
but i am getting this output
<50(1)
<50(1)
50-100(1)
100+(1)
100+(1)

Setting the values in multi-select isteven of angular js

I'm trying to use Angularjs multi-select into my project.
The following html is my multi-select div.
<div
multi-select
input-model="marks"
output-model="filters.marks"
button-label="name"
item-label="name"
tick-property="ticked"
selection-mode="multiple"
helper-elements="all none filter"
on-item-click="fClick( data )"
default-label="Select marks"
max-labels="1"
max-height="250px"
>
</div>
I know that I can use $scope.marks=data in the controller.
But the problem is $scope.marks is a global variable which I couldn't change..
Is there any way to set the values in multi-select without using the input-model?
Well, doing some tests here, i could get something with multiselecting:
var languages = ["C#", "Java", "Ruby", "Go", "C++", "Pascal", "Assembly"]; //The items.
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function($scope) {
$scope.marks = {};
for (lang in languages) {
$scope.marks[lang] = {
name: languages[lang],
marked: false
};
}
$scope.marks[3].marked = true; //mark "Go" and "C++" by default.
$scope.marks[4].marked = true;
$scope.theMarkedOnes = function() {
outp = "";
for (m in $scope.marks) {
if ($scope.marks[m].marked)
outp += $scope.marks[m].name + ", ";
}
if (outp.length == 0) {
return "(none)";
} else {
return outp.substr(0, outp.length - 2);
}
}
$scope.setMark = function(markone) {
markone.marked = !markone.marked;
}
})
*,
*:before,
*:after {
box-sizing: border-box;
}
body {
font-family: sans-serif;
font-size: 0.7em;
}
::-webkit-scrollbar {
width: 7px;
}
::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
border-radius: 10px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.5);
}
.multiselector {
background-color: #CCCCCC;
overflow-y: scroll;
width: 17em;
height: 13em;
border-radius: 0.7em;
}
.multiselector .item {
cursor: pointer;
padding: 0.2em 0.3em 0.2em 0.0em;
}
.itemtrue {
background-color: #9999AA;
}
.msshow {
background-color: #cccccc;
border-radius: 0.7em;
margin-top: 1em;
padding: 0.6em;
width: 17em;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<div class="multiselector">
<div ng-repeat="mark in marks" class="item item{{mark.marked}}" ng-click="setMark(mark)">{{mark.name}}</div>
</div>
<div class="msshow"> <b>Selected:</b> {{theMarkedOnes()}}</div>
</div>
Set & Get selected values, name and text of Angularjs isteven-multi-select
<div isteven-multi-select
input-model="marks"
output-model="filters.marks"
button-label="name"
item-label="name"
tick-property="ticked"
selection-mode="multiple"
helper-elements="all none filter"
on-item-click="fClick( data )"
default-label="Select marks"
max-labels="1"
max-height="250px">
</div>
Add items
$scope.marks= [
{ name: 'Mark I', value: 'Mark i', text: 'This is Mark 1', ticked: true },
{ name: 'Mark II', value: 'Mark ii', text: 'This is Mark 2' },
{ name: 'Mark III', value: 'Mark iii', text: 'This is Mark 3' }
];
Get selected item (on change)
$scope.fClick = function (data) {
console.log(data.name);
console.log(data.value);
console.log(data.text);
return;
}
Select item (with code)
$scope.abc = function (data) {
console.log(data.element1, data.element2);
angular.forEach($scope.marks, function (item) {
if (item.value == data.element1) {
item.ticked = true;
}
else {
item.ticked = false;
}
});
}
Deselect item (clear)
$scope.ClearClick = function () {
$scope.Filter = { selectMarks: 'Mark i' };
$scope.marks.map(function (item) {
if ($scope.Filter.selectMarks == item.value)
item.ticked = true;
else
item.ticked = false;
});
}

Resources