Dojo ValidationTextBox displays missingMessage on Enter - dojo

I am new to Dojo so please bear with me. I created a widget inheriting from ValidationTextBox and SimpleTextarea:
define([
'dojo/_base/declare',
'dijit/form/ValidationTextBox',
'dijit/form/SimpleTextarea'
],
function (declare, ValidationTextBox, SimpleTextarea) {
return declare([
ValidationTextBox,
SimpleTextarea
], {
});
}
);
I use it in a html page like this:
<textarea class="dijitTextBox dijitTextArea dijitTextBoxHover dijitTextAreaHover dijitHover"
data-dojo-attach-point="dutyReasonTextarea"
data-dojo-type="aysist/widgets/common/ValidationTextArea"
data-dojo-props="placeholder: '${nls.employee.agenda.duty_hour_reason}',required: true, missingMessage:'missingMessage: ${nls.employee.agenda.missing_duty_reason_error}', invalidMessage:'The value is not valid'"
value=""></textarea>
As I type in the textbox, no error message pops up. But as soon as I type an Enter, I get the invalidMessage. Also, I expect a red border to appear on error.
What am I doing wrong?

To get rid of the erroneous invalidMessage add a hack: an empty invalidMessage attribute to data-dojo-props. Like this:
<textarea ... data-dojo-props="...,invalidMessage:''"value=""></textarea>
To get the contents of the validatorTextarea widget to validate correctly so there is no red border when you add contents with a newline character use a validator in the custom ValidatorTextarea widget. Like his:
validator: function(value) {
return value && value.length > 0
}
Hth somebody!

Related

How can I implement v-model.number on my own in VueJS?

I have a text field component for numeric inputs. Basically I'm just wrapping v-text-field but in preparation for implementing it myself. It looks like this.
<template>
<v-text-field v-model.number = "content" />
</template>
<script>
export default {
name: 'NumericTextField',
props: [ 'value' ],
computed: {
content: {
get () { return this.value },
set (v) { this.$emit('input', f) },
},
}
}
</script>
This has generated user feedback that it's annoying when the text field has the string "10.2" in it and then backspace over the '2', then decimal place is automatically delete. I would like to change this behavior so that "10." remains in the text field. I'd also like to understand this from first principles since I'm relatively new to Vue.
So I tried this as a first past, and it's the most instructive of the things I've tried.
<template>
<v-text-field v-model="content" />
</template>
<script>
export default {
name: 'NumericTextField',
props: [ 'value' ],
computed: {
content: {
get () { return this.value },
set (v) {
console.log(v)
try {
const f = parseFloat(v)
console.log(f)
this.$emit('input', f)
} catch (err) {
console.log(err)
}
},
},
}
}
</script>
I read that v-model.number is based on parseFloat so I figured something like this must be happening. So it does fix the issue where the decimal place is automatically deleted. But... it doesn't even auto delete extra letters. So if I were to type "10.2A" the 'A' remains even though I see a console log with "10.2" printed out. Furthermore, there's an even worse misfeature. When I move to the start of the string and change it to "B10.2" it's immediately replaced with "NaN".
So I'd love to know a bunch of things. Why is the body of the text body immediately reactive when I change to a NaN but not immediately reactive when I type "10.2A"? Relatedly, how did I inadvertently get rid of the auto delete decimal place? I haven't even gotten to that part yet. So I'm misunderstanding data flow in Vue.
Lastly, how can I most simply provide a text box that's going to evaluate to a number for putting into my data model but not have the annoying auto delete of decimal places? The existing functionality doesn't auto delete trailing letters so I'm guessing the auto delete of decimal places was a deliberate feature that my users don't like.
I'm not 100% sure of any of this, but consider how v-model works on components. It basically is doing this:
<v-text-field
v-bind:value="content"
v-on:input="content = $event.target.value"
/>
And consider how the .number modifier works. It runs the input through parseFloat, but if parseFloat doesn't work, it leaves it as is.
So with that understanding, I would expect the following:
When you type in "10.2" and then hit backspace, "10." would be emitted via the input event, parseFloat("10.") would transform it to 10, v-on:input="content = $event.target.value" would assign it to content, and v-bind:value="content" would cause the input to display "10". So then, this is the expected behavior.
When you type in "10.2" and then hit "A", "10.2A" would be emitted via the input event, parseFloat("10.2A") would transform it to 10.2, v-on:input="content = $event.target.value" would assign it to content, and v-bind:value="content" would cause the input to display "10.2". It looks like it's failing at that very last step of causing the input to display "10.2", because the state of content is correctly being set to 10.2. If you use <input type="text" v-model.number="content" /> instead of <v-text-field v-model.number="content" />, once you blur, the text field successfully gets updated to "10.2". So it seems that the reason why <v-text-field> doesn't is due to how Vuetify is handling the v-bind:value="content" part.
When you type in "10.2" and then enter "B", in the beginning, "B10.2" would be emitted via the input event, parseFloat("B10.2") would return NaN, and thus the .number modifier would leave it as is, v-on:input="content = $event.target.value" would assign "B10.2" to content, and v-bind:value="content" would cause the input to display "B10.2". I agree that it doesn't seem right for parseFloat("10.2A") to return 10.2 but parseFloat("B10.2") to return "B10.2".
Lastly, how can I most simply provide a text box that's going to evaluate to a number for putting into my data model but not have the annoying auto delete of decimal places?
Given that the default behavior is weird, I think you're going to have to write your own custom logic for transforming the user's input. Eg. so that "10.2A" and "B10.2" both get transformed to 10.2 (or are left as is), and so that decimals are handled like you want. Something like this (CodePen):
<template>
<div id="app">
<input
v-bind:value="content"
v-on:input="handleInputEvent($event)"
/>
<p>{{ content }}</p>
</div>
</template>
<script>
export default {
data() {
return {
content: 0,
};
},
methods: {
handleInputEvent(e) {
this.content = this.transform(e.target.value);
setTimeout(() => this.$forceUpdate(), 500);
},
transform(val) {
val = this.trimLeadingChars(val);
val = this.trimTrailingChars(val);
// continue your custom logic here
return val;
},
trimLeadingChars(val) {
if (!val) {
return "";
}
for (let i = 0; i < val.length; i++) {
if (!isNaN(val[i])) {
return val.slice(i);
}
}
return val;
},
trimTrailingChars(val) {
if (!val) {
return "";
}
for (let i = val.length - 1; i >= 0; i--) {
if (!isNaN(Number(val[i]))) {
return val.slice(0,i+1);
}
}
return val;
},
},
};
</script>
The $forceUpdate seems to be necessary if you want the input field to actually change. However, it only seems to work on <input>, not <v-text-field>. Which is consistent with what we saw in the second bullet point. You can customize your <input> to make it appear and behave like <v-text-field> though.
I put it inside of a setTimeout so the user sees "I tried to type this but it got deleted" rather than "I'm typing characters but they're not appearing" because the former does a better job of indicating "What you tried to type is invalid".
Alternatively, you may want to do the transform on the blur event rather than as they type.

Why does variable substitution not work for my case?

I'm trying to create a custom widget using templates, but variable substitution does not seem to be working for me.
I can see the property value being updated inside the widget, but the DOM does not change. For example, when I use the get() method, I can see the new value of the widget's property. However, the DOM never changes its value.
Here is my template:
<div class="outerContainer">
<div class="container">
<span class="mySpan">My name is ${name}</span>
</div>
</div>
Now, here is my widget code:
define([
"dojo/_base/declare",
"dijit/_WidgetBase",
"dijit/_TemplatedMixin",
"dojo/text!/templates/template.html",
], function (declare, _WidgetBase, _TemplatedMixin, template) {
return declare([_WidgetBase, _TemplatedMixin], {
templateString: template,
name: "",
constructor: function (args) {
console.log("calling constructor of the widget");
this.name = args.name;
},
startup: function() {
this.inherited(arguments);
this.set("name", "Robert"); // this does not work
},
postCreate: function() {
this.inherited(arguments);
this.set("name, "Robert"); // this does not work either
},
_setNameAttr: function(newName) {
// I see this printed in the console.
console.log("Setting name to " + newName);
this._set("name", newName);
// I also see the correct value when I get()
console.log(this.get("name")); // This prints Robert
}
});
});
I was expecting the DOM node to say "My name is Robert" i.e. the new value, but it never updates. Instead, it reads "My name is ". It does not overwrite the default value.
I'm sure I'm missing a silly step somewhere, but can someone help me figure out what?
You should bind the property to that point in the dom. So you will need to change the template to this:
<span class="mySpan">My name is <span data-dojo-attach-point='nameNode'></span></span>
And in your widget you should add this function to bind it whenever name changes:
_setNameAttr: { node: "nameNode", type: "innerHTML" },
Now when name changes, it will change the innerHTML of the nameNode inside your mySpan span. If you need to know more about this binding I recommend checking the docs out.
Hope this helps!

DataTables: Changing the appearance of the editable cell

Can someone help me to make editable cell "visible", so it could be clear it can be edited? Right now it looks like a simple text and nothing visually suggests, that it can be edited...I´d like to make it look like a standard text field.
This should work:
var oTable = $('#example').dataTable( {
"bServerSide": true,
"sAjaxSource": "/url/",
"fnDrawCallback": function () {
$('#example tbody td').editable( 'url', { // simple editable initialization
"height": "14px",
});
$('#example tbody tr').each(function() {
$.each(this.cells, function(){
$(this).click() //by default all td's have bind for click function, so we simulate clicks for every td
});
});
$('#example tbody td input').live('click', function(){
$(this).select() // to select input
})
}
});
$.editable.types.defaults.reset = function (){ //this function disables reset input editing after submiting
}
UPDATE:
I made a test sample here http://jsfiddle.net/94BZV/31/
Don't forget to put correct url in init of editable to get correct answer passed back to edit field.
are you want this in ASP.net or what? if yes then,if your text is in GridView then you have to set EDITINDEX Value to the rowindex value of the list,as if the EDITINDEX value is -1 then it is static mode then every thing will be displayed in label so you should change it value to Greater Than >-1 Then The Controls will be displayed in TextBoxes So then You can edit the Value in the Controls"

Using dijit.InlineEditBox with dijit.form.Select

I'm trying to use a dijit.form.Select as the editor for my dijit.InlineEditBox. Two problems / unexpected behavior seem to occur:
Inconsistently, the InLineEditBox doesn't have the initial value set as selected
Consistently, after selecting a choice, the value that should be hidden is shown instead of the label.
The width isn't set to 130px
Here's working code: http://jsfiddle.net/mimercha/Vuet8/7/
The jist
<span dojoType="dijit.InlineEditBox" editor="dijit.form.Select"
editorParams="{
options: [
{label:'None',value:'none'},
{label:'Student',value:'stu'},
{label:'Professor',value:'prof',selected:true},
],
style:'width:1000px;',
}"
editorStyle="width: 1000px;"
>
</span>
Any help is greatly appreciated! Thanks!
Okay, after a few MORE hours struggling with the mess that is dijit.InlineEditBox, I think I have the solution to the remaining issue (#2).
EDIT: My first solution to #2 is still flawed; the implementation at http://jsfiddle.net/kfranqueiro/Vuet8/10/ will never return the actual internal value when get('value') is called.
EDIT #2: I've revamped the solution so that value still retains the real (hidden) value, keeping displayedValue separate. See if this works better:
http://jsfiddle.net/kfranqueiro/Vuet8/13/
First, to recap for those who weren't on IRC:
Issue #1 was happening due to value not being properly set as a top-level property of the InlineEditBox itself; it didn't pick it up properly from the wrapped widget.
Issue #3 was happening due to some pretty crazy logic that InlineEditBox executes to try to resolve styles. Turns out though that InlineEditBox makes setting width particularly easy by also exposing it as a top-level numeric attribute. (Though IINM you can also specify a percentage as a string e.g. "50%")
Now, issue #2...that was the killer. The problem is, while InlineEditBox seems to have some logic to account for widgets that have a displayedValue attribute, that logic is sometimes wrong (it expects a displayedValue property to actually exist on the widget, which isn't necessarily the case), and other times missing entirely (when the InlineEditBox initializes). I've worked around those as best I could in my own dojo.declared extensions to InlineEditBox and the internal widget it uses, _InlineEditor - since generally it's a good idea to leave the original distribution untouched.
It's not pretty (neither is the underlying code I dug through to understand and come up with this), but it seems to be doing its job.
But man, this was rather interesting. And potentially pertinent to my interests as well, as we have used this widget in our UIs as well, and will be using it more in the future.
Let me know if anything backfires.
hm...
<span dojoType="dijit.InlineEditBox" editor="dijit.form.Select"
editorParams="{
options: [
{label:'None',value:'none'},
{label:'Student',value:'stu'},
{label:'Professor',value:'prof',selected:true},**<<<<** and this comma is for?
],
style:'width:1000px;',**<<<<** and this comma is for?
}"
editorStyle="width: 1000px;"
>
</span>
Also, when using dijit.form.Select, selected value is not attr "selected" but value.
And if you enter prof inside <span ...blah > prof </span> than your proper selected option will be selected ;)
Dijit select checks for VALUE, not attr.
This may be fixed in recent Dojo - see http://bugs.dojotoolkit.org/ticket/15141 - but using 1.7.3 I found this worked:
In my app directory, at the same level as dojo, dijit and dojox, I created a file InlineSelectBox.js which extends InlineEditBox with code to set the HTML on the associated domNode from the value of the Dijit, and which wires up that code to the onChange() event:
define(["dijit/InlineEditBox",
"dijit/form/Select",
"dojo/on",
"dojo/_base/declare",
"dojo/_base/array"
],
function(InlineEditBox, Select, on, declare, array){
return declare(InlineEditBox, {
_setLabel: function() {
array.some(this.editorParams.options, function(option, i){
if (option.value == this.value) {
this.domNode.innerHTML = option.label;
return true;
}
return false;
}, this);
},
postMixInProperties: function(){
this.inherited(arguments);
this.connect(this, "onChange", "_setLabel");
},
postCreate: function(){
this.inherited(arguments);
this._setLabel();
}
});
});
Then, in my view script:
require(["dojo/ready",
"app/InlineSelectBox",
"dijit/form/Select"
],
function(ready, InlineSelectBox, Select){
ready(function(){
// Add code to set the options array
var options = [];
// Add code to set the initial value
var initialValue = '';
var inlineSelect = new InlineSelectBox({
editor: Select,
editorParams: {options: options},
autoSave: true,
value: initialValue
}, "domNodeToAttachTo");
});
});
I was dealing with this situation a few months ago, and not finding a resolution i made my own algorithm.
I put a div with an event on Onclick that build programatically a Filtering Select on that div with the store i want to use.
function create(id,value){
var name = dojo.byId(id).innerHTML;
dojo.byId(id).parentNode.innerHTML = '<div id="select"></div>';
new dijit.form.FilteringSelect({
store: store,
autoComplete: true,
invalidMessage:"Invalid Selection",
style: "width: 80px;",
onBlur: function(){ },
onChange: function(){ },
required: true,
value: value,
disabled: false,
searchAttr: "name",
id: "status"+id,
name: "status"
},"select");
dijit.byId('status'+id).focus();
}
I used the onBlur event to destroy the widget and the onchange to save by xhr the new value.
The focus is below because the onBlur was not working properly.
note: the function is not complete.

How to show a checkbox in a dojo datagrid?

How to show a checkbox in a dojo datagrid?
I would suggest setting cellType to dojox.grid.cells.Bool, instead of the formatter.The formatter gives you much freedom, but also the responsibility of gathering the data from all the checkboxes (for all the rows) afterwards. Something like this as a structure-entry should do the trick:
{
name: "is awesome?",
width: "auto",
styles: "text-align: center",
type: dojox.grid.cells.Bool, editable: true
}
Please make sure to use a write-store (like ItemFileWriteStore) and not just a read-store, otherwise you will be disabled to actually check the checkbox :)
Use formatter function as described in Widgets Inside dojo.DataGrid
You can return new dijit.form.Checkbox from formatter function in dojo 1.4
You need the IndirectSelection plugin for the EnhancedGrid, here's a fiddle: http://jsfiddle.net/raybr/w3XpA/5/
You can use something like this, with Json
HTML
<table id="myGrid" dojoType="dojox.grid.DataGrid"
clientSort="true" autoHeight="true" autoWidth="true">
<script type="dojo/method">
showFields();
</script>
</table>
DOJO
showFields:function () {
dojo.xhrPost({
url:"/getFields.do",
timeout:2000,
handleAs:"json",
load:dojo.hitch(this, "displayInGrid")
});
},
displayInGrid:function (jsonResult) {
var dataStore = new dojo.data.ItemFileReadStore(
{ data:jsonResult }
);
var checkboxLayout = [
[
{name:'ID', field:"id" },
{name:'Value', field:"id", formatter:this.addCheckBox}
]
];
var grid = dijit.byId("myGrid");
grid.setStructure(checkboxLayout);
grid.setStore(dataStore);
},
addCheckBox:function (val) {
var checkbox = "<input type='checkbox' name='myfields' value='" + val + "/>";
return checkbox;
},
If you are trying to show a checkbox selector on each row of the grid you can follow this tutorial
http://dojotoolkit.org/documentation/tutorials/1.8/working_grid/demo/selector.php
If the type of the cell is a boolean, then its value is displayed as either the string true or false. If a check box is desired, setting the cellType to be dojox.grid.cells.Bool and marking it as editable will make a checkbox appear.
http://dojotoolkit.org/reference-guide/1.9/dojox/grid/DataGrid.html#editing-cells
From markup, do like this for the desired result:
<th field="booleanField" cellType="dojox.grid.cells.Bool" editable="true">Checkbox field</th>