Angular Bootstrap UI Timepicker entering invalid time - angular-ui-bootstrap

I'm using Angular Bootstrap UI Timepicker and if I enter 50 in the hours field, it highlights the field red, but nevertheless I get a valid date out of it that looks just like that Tue Nov 15 2016 05:00:55 GMT+0100.
Any ideas what I can do? Thanks!

For that matter you could consider to limit the hour and minute input values, here is how to customize it for Timepicker
introduce a custom template and specify the min, max and validate-value attributes for hour and minute input elements, for example:
<input type="text" placeholder="HH" validate-value min="1" max="12" ng-model="hours" ng-change="updateHours()" class="form-control text-center" ng-readonly="::readonlyInput" maxlength="2" tabindex="{{::tabindex}}" ng-disabled="noIncrementHours()" ng-blur="blur()">
implement validate-value directive to limit the number values in input element:
.directive('validateValue', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
ngModelCtrl.$parsers.unshift(function(viewValue) {
var min = Number(eval(attrs.min));
var max = Number(eval(attrs.max));
var value = Number(viewValue);
var valid = (!isNaN(value) && value >= min && value <= max);
if (!valid) {
var currentValue = ngModelCtrl.$modelValue.toString();
ngModelCtrl.$setViewValue(currentValue);
ngModelCtrl.$render();
return currentValue;
}
else {
return viewValue;
}
});
}
};
})
Demo

Related

Svelte: How to bind a formatted input field to a property

First of all: Svelte is still new to me. I hope the question is not too trivial.
Within a simple component I want to use the content of a formatted input field for a calculation.
For example:
In the input field a Euro amount should be displayed formatted (1.000).
Next to it a text with the amount plus VAT should be displayed (1.190).
How I do this without formatting is clear to me. The example looks like this:
export let net;
export let vat;
$: gross = net + (net * vat / 100);
$: grossPretty = gross.toLocaleString('de-DE',{ minimumFractionDigits: 0, maximumFractionDigits: 0 });
with a simple markup like this:
<form>
<label>Net amount</label>
<input type="text" step="any" bind:value={net} placeholder="Net amount">
</form>
<div>
Gros = {grossPretty} €
</div>
In vue i used a computed property. Its getter delivers the formatted string and its setter takes the formatted string and saves the raw value.
(In data() I define net, in the computed properties i define netInput. The input field uses netInput as v-model).
It looks like this:
netInput: {
get(){
return this.net.toLocaleString('de-DE',{ minimumFractionDigits: 0, maximumFractionDigits: 0 });
},
set(s){
s = s.replace(/[\D\s._-]+/g, "");
this.net = Number(s);
}
}
How can I handle it in svelte?
You can do something somewhat similar, you create another computed variable that stores the deformatted string from the input field and is used in the calculation instead of the direct input
export let net;
export let vat;
$: net_plain = Number(net.replace(/[\D\s._-]+/g, ""));
$: gross = net_plain + (net_plain * vat / 100);
$: grossPretty = gross.toLocaleString('de-DE',{ minimumFractionDigits: 0, maximumFractionDigits: 0 });
But maybe find a better name for the variable :)
Thanks to Stephane Vanraes I found a solution.
It has not the charm of the vue approach but it's ok. First I inserted 'net_plain'. To have the input field formatted during input, I added an event listener for the keyup event.
<input type="text" step="any" bind:value={net} on:keyup={handleKeyUp} placeholder="Net amount">
The event is handled from the function handleKeyUp as follows:
function handleKeyUp(event){
if ( window.getSelection().toString() !== '' ) {
return;
}
// ignore arrow keys
let arrows = [38,40,37,39];
if ( arrows.includes( event.keyCode)) {
return;
}
let input = event.target.value.replace(/[\D\s._-]+/g, "");
input = input ? parseInt( input, 10 ) : 0;
event.target.value = ( input === 0 ) ? "" : input.toLocaleString( "de-DE" );
}
BUT: If anyone has a solution using getter and setter I would appreciate the anwer!

Input range slider not working on iOS Safari when clicking on track

I have a pretty straight-forward range input slider. It works pretty well on all browsers except on iOS Safari.
The main problem I have is when I click on the slider track, it doesn't move the slider. It merely highlights the slider. It works fine when dragging the thumb. Any ideas on how to fix this?
<div class="slider-wrap">
<div id="subtractBtn"></div>
<input type="range" class="slider">
<div id="addBtn"></div>
</div>
For those still looking for a javascript only fix like I did. I ended up just making a "polyfill" for this; it relies on the max attribute of the slider and determines the best step to force the input range on iOS. You can thank me later :)
var diagramSlider = document.querySelector(".diagram-bar");
function iosPolyfill(e) {
var val = (e.pageX - diagramSlider.getBoundingClientRect().left) /
(diagramSlider.getBoundingClientRect().right - diagramSlider.getBoundingClientRect().left),
max = diagramSlider.getAttribute("max"),
segment = 1 / (max - 1),
segmentArr = [];
max++;
for (var i = 0; i < max; i++) {
segmentArr.push(segment * i);
}
var segCopy = segmentArr.slice(),
ind = segmentArr.sort((a, b) => Math.abs(val - a) - Math.abs(val - b))[0];
diagramSlider.value = segCopy.indexOf(ind) + 1;
}
if (!!navigator.platform.match(/iPhone|iPod|iPad/)) {
diagramSlider.addEventListener("touchend", iosPolyfill, {passive: true});
}
<input type="range" max="6" min="1" value="1" name="diagram selector" class="diagram-bar" />
Add the CSS property, -webkit-tap-highlight-color: transparent to the CSS of the element or the complete html page. This will remove the troublesome highlight effect on an element when it is tapped on a mobile device.
Enhanced version of the solution presented by Cameron Gilbert. This implementation works for sliders with a min value set to a negative number and optional a step size set.
For those not working with typescript I leave it to you to convert to plain javascript.
if (!!navigator.platform.match(/iPhone|iPad|iPod/)) {
mySlider.addEventListener(
"touchend",
(touchEvent: TouchEvent) => {
var element = touchEvent.srcElement as HTMLInputElement;
if (element.min && element.max && touchEvent.changedTouches && touchEvent.changedTouches.length > 0) {
const max = Number(element.max);
const min = Number(element.min);
let step = 1;
if (element.step) {
step = Number(element.step);
}
//Calculate the complete range of the slider.
const range = max - min;
const boundingClientRect = element.getBoundingClientRect();
const touch = touchEvent.changedTouches[0];
//Calculate the slider value
const sliderValue = (touch.pageX - boundingClientRect.left) / (boundingClientRect.right - boundingClientRect.left) * range + min;
//Find the closest valid slider value in respect of the step size
for (let i = min; i < max; i += step) {
if (i >= sliderValue) {
const previousValue = i - step;
const previousDifference = sliderValue - previousValue;
const currentDifference = i - sliderValue;
if (previousDifference > currentDifference) {
//The sliderValue is closer to the previous value than the current value.
element.value = previousValue.toString();
} else {
element.value = i.toString();
}
//Trigger the change event.
element.dispatchEvent(new Event("change"));
break;
}
}
}
},
{
passive: true
}
);
}
Safari 5.1 + should support type "range" fully - so it's weird it's not working.
did you try adding min/max/step values ? what about trying to use only the pure HTML attribute without any classes that might interfere - try pasting this code and run it on a Safari browser
<input type="range" min="0" max="3.14" step="any">
it should be working - if it does, it's probably something related to your css, if not try using one of the pure HTML examples here:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/range
Try using jQuery Mobile? The workaround is obnoxious, and I'm pretty sure there's no way to use the native interface with standard HTML. It appears from other threads, you could do an elaborate CSS/JS solution.

How to preselect an item using Javascript when the page renders

I have a drupal rendered webform that generates the following HTML for a SELECT list. The list is essentially for booking a table in a restaurant. My client wants me to preselect the meal based on the time of the day. So if its between midnight and 3:00 pm Lunch should be preselected automatically. After 3:00 pm till 10:30pm the form should display with dinner preselected.
<select class="form-select required" name="submitted[meal]" id="edit-submitted-meal">
<option selected="selected" value="1">Lunch</option>
<option value="2">Dinner</option>
<option value="3">Sunday Dining</option>
</select>
I created the following JS snippet hoping to achieve the objective but it doesn't seem to work on Page load
window.onload() {
var today = new Date("<?php echo date("Y-m-d H:i:s"); ?>");
var day = date.getDay();
var hour = date.getHours();
var meallist = document.getElementbyId("#edit-submitted-meal");
if (day == 0) {
meallist.options[3].selected==true;
}
else {
if (hour > 15 && hour < 22) {
meallist.options[2].selected==true;
}
else if (hour > 22 && hour < 24 {
meallist.options[1].selected==true;
}
else if (hour > 0 && hour < 15 {
meallist.options[1].selected==true;
}
}
}
Would appreciate any help. Thank you in advance.
PS : The PHP code injects the date into the javascript so when the page is rendered the line becomes var today = new Date("2013-01-15 15:49:45");
You have an error in your javascript syntax
window.onload(){
//your code here
}
should be
window.onload = (function(){
//your code here
});
Also when using document.getElementById you don't want to include the '#'
and for setting a variable as in
meallist.options[1].selected==true;
you only want to use a single =
meallist.options[1].selected=true;
Also bear in mind that the options array is 0 based. E.g options value=3 is actually
meallist.options[2] not [3]
A simplified version can be found here
http://jsfiddle.net/N7Yhr/
Do you have any other errors in your console window (firebug etc)?

How to synchronize sliders' values?

I use jquery mobile sliders:
<div data-role="fieldcontain">
<input type="range" name="slider1" id="slider1" value="0" min="0" max="255" />
</div><br><br>
<div data-role="fieldcontain">
<select name="switcher1" id="switcher1" data-role="slider">
<option value="0">Off</option>
<option value="255">On</option>
</select>
</div>
It should work in the following way:
if switcher1 is touched, then slider1 value should be set either to 0 or to 255;
if slider1 value is changed, then (a) if it is = 0, then switcher1 should be set to 0, (b) else switcher1 value should be set to 255.
I've tried to do so with change event (the same is used for switcher1 change()):
var slider1_val = "0";
$('#slider1').change(function () {
sVal = $(this).val();
if (slider1_val !== sVal) {
$("#slider1").val(sVal).slider("refresh");
if (sVal == 0) {
$("#switcher1").val(0).slider("refresh");
} else {
$("#switcher1").val(255).slider("refresh");
}
slider1_val = sVal;
}
});
But looks like each call of refresh calls change event, so I am getting infinite loop.
It should work in the following way:
if switcher1 is touched, then slider1 value should be set either to 0 or to 255;
if slider1 value is changed, then (a) if it is = 0, then switcher1 should be set to 0, (b) else switcher1 value should be set to 255.
I've tried to do so with change event (the same is used for switcher1 change()):
The fact that you have two very different criteria for changing each control should tip you off that the change event handlers should be different as well. Using the same handlers leads to the infinite loop you are experiencing. The code below accounts for the strict change criteria you've provided. Note that the slider1 change handler changes switcher1 only if it needs to be changed (based on your criteria), not every time it is called. Also, note that in the slider1 change handler, switcher1_val is set before calling refresh, so that in case .slider('refresh') does call the change handler, the change handler will not do anything, because switcher1_val is already updated.
var linkSliders = function(sliderId, switcherId){
var slider = $('#'+sliderId),
switcher = $('#'+switcherId);
var min = Math.min(switcher[0].options[0].value, switcher[0].options[1].value),
max = Math.max(switcher[0].options[0].value, switcher[0].options[1].value);
var sliderVal = switcherVal = min;
// set the slider min/max to be the same as the switcher's, just in case they're different
slider.attr('max', max).attr('min', min).slider('refresh');
slider.change(function(){
var sVal = $(this).val();
if(sliderVal != sVal){
if( sVal == min && switcherVal!=min){
switcherVal=min;
switcher.val(min).slider('refresh');
}else if(sVal>min && switcherVal!=max){
switcherVal=max;
switcher.val(max).slider('refresh');
}
sliderVal = sVal;
}
});
switcher.change(function(){
var sVal = $(this).val();
if(switcherVal != sVal){
slider.val(sVal).slider('refresh');
switcherVal = sVal;
}
});
};
linkSliders('slider1','switcher1');
See the live example.
Hope this helps.
Update: As requested, the example has been modified to make it more general.

Formatting time for user input in ASP.Net MVC

I have a form that users are allowed to enter time values in (say, hours spent performing some task). A business requirement is that the time be entered in either hh:mm format, or decimal format. In either case, there could potentially be quite a bit of client side javascript for display "helping"--showing totals, validating against other input, etc.
So, for instance, one user might enter "8:30" for Eight Hours Thirty Minutes, while another might enter "8.5" to mean the same thing. I'm looking for something that would let me keep the form/validation duplication to a minimum.
What are the best ways to go about this with the model and the view?
The regular expression to allow both formats wouldn't be that complicated. I would perform that simple validation client-side via javascript. Beyond that, you may want to add some business validation (at the business object level) for this.
I used jQuery to create a slider that would change the time in the input box in the right format.
In my View File, Create.aspx, put the following jquery function somewhere in the beginning of the body.
<script>
$(function () {
$("#slider").slider({
value: 9,
min: 0,
max: 1440,
step: 15,
slide: function (event, ui) {
var hours = Math.floor(ui.value / 60);
var minutes = ui.value - (hours * 60);
var ampm = "AM";
if (hours == 12) { ampm = "PM"; }
else if (hours == 0) { hours = 12; ampm = "AM"; }
else if (hours > 12) { hours = hours - 12; ampm = "PM"; }
if (hours < 10) hours = '0' + hours;
if (minutes < 10) minutes = '0' + minutes;
$("#work_StartTime").val(hours + ':' + minutes + ' ' + ampm);
}
});
});
</script>
then down in the body of the same page put a div near the textbox for time input. A slider will show up at that div
<div class="editor-field">
<%: Html.EditorFor(model => model.work.StartTime)%>
<div id="slider"></div>
<%: Html.ValidationMessageFor(model => model.work.StartTime)%>
</div>
this will give you a slider. In the above javascript code change the step:15, makes increments to be 15 minutes.
This is obviously a client side validation. A server side validation should also be implemented of course.

Resources