NVDA reads the first letter of the word, then the word from the autocomplete dropdown list - jaws-screen-reader

I am working on .NET MVC project and I have problem with NVDA and JAWS reader on the dropdown list. It is the dropdown autocomplete list, and when I am navigating with the keyboard, it was reading double values from the dropdown list.
Then I have added aria-hidden="true", and now it is reading the first alphabet of the value, then the value. For example, this dropdown list:
car
apple
watch
It is reading this:
c
car
a
apple
w
watch
What should I do to read only values?
Code from cshtml:
<input id="client" aria-hidden="true" type="text" class="form-control" data-html="true" placeholder="Enter #Model.ClientTitle">
Code from JS:
$('#client').autocomplete({
source: function (request, response) {
response($.map(clients, function (item, key) {
return {
label: item.Name + " (" + item.ClientId + ")",
value: item.Name + " (" + item.ClientId + ")",
}
}
}));
},
select: function (event, ui) {
event.preventDefault();
if (ui.item.value === "") {
$('#client').val(null);
return false;
}
$('#client').val(ui.item.label);
},
response: function (event, ui) {
if (!ui.content.length) {
var noResult = { value: "", label: "No matches found." };
ui.content.push(noResult);
}
},
minLength: 3,
delay: 500
});

Related

Correct way to show calculated values on vuetify forms

I begin to use vuetify some days ago.
Now i'm playing with forms and datatables.
I want to show on a form calculated values based on one database record and i don't know if i'm doing right.
The record returned by an api have this columns:
senderCuip
senderDescription
brokerCuip
brokerDescription
recipientCuip
recipientDescription
originDescription
originCity
originState
destinationDescription
destinationCity
destinationState
and i want to show as:
Sender as senderCuip (senderDescription)
Broker as brokerCuip (brokerDescription)
Recipient as recipientCuip (recipientDescription)
Origin as originDescription (originCity, originState)
Destination as destinationDescription (destinationCity, destinationState)
Example:
senderCuip: '20224528325'
senderDescription: 'SENDER SA'
brokerCuip: '30455298762'
brokerDescription: 'BROKER SA'
recipientCuip: '33521452363'
recipientDescription: 'RECIPIENT
SA'
originDescription: 'ORIGIN DESCRIPTION'
originCity: 'ORIGIN CITY'
originState: 'ORIGEN STATE'
destinationDescription: 'DESTINATION DESCRIPTION'
destinationCity: 'DESTINATION CITY'
destinationState: 'DESTINATION STATE'
must be showed as:
Sender: 20224528325 (SENDER SA)
Broker: 30455298762 (BROKER SA)
Recipient: 33521452363 (RECIPIENT SA)
Origin: ORIGIN DESCRIPTION (ORIGIN CITY, ORIGEN STATE)
Destination: DESTINATION DESCRIPTION (DESTINATION CITY, DESTINATION STATE)
I'm using five computed properties.
The computed properties for Sender, Broker, and Recipient use the same format. The same applies for the computed properties for Origin and Destination.
I'm doing in this way:
computed: {
sender: function () {
return this.item.senderCuip + ' (' + this.item.senderDescription + ')';
},
broker: function () {
return this.item.brokerCuip + ' (' + this.item.brokerDescription + ')';
},
recipient: function () {
return this.item.recipientCuip + ' (' + this.item.recipientDescription + ')';
},
origin: function () {
return this.item.originDescription + ' (' + this.item.originCity + ', ' + this.item.originState + ')';
},
destination: function () {
return this.item.destinationDescription + ' (' + this.item.destinationCity + ', ' + this.item.destinationState + ')';
}
}
but i think that this can be done in more effective ways. I understand that computed properties cannot receive parameters or call methods to do something like that:
methods: {
participator(cuip, description) {
return cuip + ' (' + description + ')'
},
location(description, city, state) {
return description + ' (' + city + ', ' + state + ')';
}
}
computed: {
sender: function (cuip, description) {
return participator(cuip, description);
}
}
Codepen link
Similar case happens on a datatable, in this case i use templates instead of computed properties, but the problem is the same, repetitive code:
<template v-slot:item.sender="{ item }">{{ item.senderCuip }} ({{ item.senderDescription }})</template>
<template v-slot:item.broker="{ item }">{{ item.brokerCuip }} ({{ item.brokerDescription }})</template>
<template v-slot:item.recipient="{ item }">{{ item.recipientCuip }} ({{ item.recipientDescription }})</template>
<template v-slot:item.origin="{ item }">{{item.originDescription }} ({{ item.originCity }} , {{ item.originState }})</template>
<template v-slot:item.destination="{ item }">{{item.destinationDescription }} ({{ item.destinationCity }} , {{ item.destinationState }})</template>
I'm doing well or there are best options?
Regards.
You could try out generate those properties dynamically to simplify your app (this saves time when it grows), using a reduce function as I did below.
Check it on Codepen or in the snippet above:
Note: The snippet and the codepen are a little bit different in layout
const createComputedWithInfo = (properties) => (
Object
.getOwnPropertyNames(properties)
.reduce((computedProperties, property) => {
const primaryInfo = properties[property].primary
const secondaryInfo = properties[property].secondary
computedProperties[property] = `${primaryInfo} ( ${Array.isArray(secondaryInfo) ? secondaryInfo.join(', ') : secondaryInfo} )`
return computedProperties
}, {})
);
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
item: {
number: "214852145218",
date: "2020-01-27",
properties: {
sender: {
primary: "20224528325",
secondary: "SENDER SA"
},
broker: {
primary: "30455298762",
secondary: "BROKER SA"
},
recipient: {
primary: "33521452363",
secondary: "RECIPIENT SA"
},
origin: {
primary: "ORIGIN DESCRIPTION",
secondary: ["ORIGIN CITY", "ORIGEN STATE"]
},
destination: {
primary: "DESTINATION DESCRIPTION",
secondary: ["DESTINATION CITY", "DESTINATION STATE"]
}
},
}
}),
computed: {
itemProperties: function () {
return {
...createComputedWithInfo(this.item.properties)
}
}
}
});
input {
width: 100%
}
<script src="https://cdn.jsdelivr.net/npm/babel-polyfill/dist/polyfill.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.2.6/dist/vuetify.min.js"></script>
<div id="app">
<v-app id="inspire">
<v-form
>
<v-text-field
v-model="itemProperties.sender"
></v-text-field>
<v-text-field
v-model="itemProperties.broker"
></v-text-field>
<v-text-field
v-model="itemProperties.recipient"
></v-text-field>
<v-text-field
v-model="itemProperties.origin"
></v-text-field>
<v-text-field
v-model="itemProperties.destination"
></v-text-field>
</v-form>
</v-app>
</div>

How to put an if condition under columns in kendo grid

Can we add a if Condition inside the column while describing the columns of the grid? Whats wrong in this code
I want to display one button in the grid under a column ,if length of the text exceeds more than 40char.
I am trying to put an if condition if the content/data is less than 40 char then display the content else display a button , On click of button open a pop-up to display the complete content inside that pop-up?
How we can put the command conditionally to display the button?
Here is my code
columns: [{
field: "id",
title: "ID",
width: "100px"
}, // fields in the grid
{
field: "name",
title: "Name",
width: "100px"
}, {
field: "remarks",
title: "Remarks",
width: "160px", // under this column button will be displayed in each
var length = 40;
if (data.remarks.length > length) { //here this condition seems to be wrong, is there any other way to display the button for this condition
command: {
name: "remarks",
text: "Remarks",
click: function (e) {
var tr = $(e.target).closest("tr");
var data = this.dataItem(tr);
var win = $('#remarksWindow');
win.html(data.remarks);
if (!win.data('kendoWindow')) {
win.kendoWindow({
width: '600px',
height: '200px',
title: 'Remarks',
actions: ['Close']
});
}
win.parent().css({
top: e.pageY - 50,
left: e.clientX - 640,
width: '600px',
height: '200px'
});
win.data('kendoWindow').open(); // open the pop-up which contains the data
return false;
}
}
}
}
},
First of all, you have a syntax error in JavaScript. Note that you can't put statements or declarations between the properties of an object:
var obj = {
a: 1,
if (true) {
b: 2;
}
}
Or
var obj = {
a: 1,
var b = 1;
}
The examples above doesn't works. So in your column property you have to use a template property:
{
field: "remarks",
title: "Remarks",
width: "160px",
template: "" // <- here goes your logic
}
So a simple template can be set as a string containing html with JavaScript logic, e.g.:
# if (remarks.length > 40) { # <input type='button' class='btn-remarks' /> # } #
Yes, you will have to set the button html by yourself. There is no way to add a condition to a command button(and that is a shame, actually).
You can check how template works here.
Then your column item should be:
{
field: "remarks",
title: "Remarks",
width: "160px",
template: "# if (remarks.length > 40) { # <input type='button' class='remarks' /> # } #"
}
Then you have to set the event for all your buttons(probably in the dataBound event):
$("#yourGrid").on("click", ".btn-remarks", function()
{
// all your click logic here
});
Give it a try and tell me what happens.
Hopefully this dojo is what you are looking for: http://dojo.telerik.com/ETora
(I have used one of Telerik's grid demos and modified to show you the principles)
The functionality you are looking for can be achieved by two means:
1) Apply a client Template to the column
2) Add a databound event that then hooks up the buttons
columns:[ {
field: "CompanyName",
title: "Company Name",
template: "#= displayTextorButton(data.CompanyName) #"
}]
function displayTextorButton(data){
var retString = '';
console.log(data);
if(data !== null && data !== undefined)
{
if(data.length > 20)
{
retString = ' <button type="button" class="btn btn-xs btn-primary"' +
'data-toggle="popover" data-placement="auto right" data-container="body" ' +
'data-content="' + kendo.htmlEncode(data) + '"' +
'data-title="Running Log Information" data-trigger="click" data-role-me="content-popover" > <span class="glyphicons glyphicons-pencil"></span> View</button>';
}
else
{
retString = '<span>' + data + '</span>';
}
}else
{
retString = '<span> - </span>';
}
return retString;
}
so the first bit I have done is added a template to the Company Name column that checks if the name is more than 20 characters if it is then it will display a button if it isn't then it will display the text as normal.
function(e){
$('button[data-role-me="content-popover"]').popover({ trigger: "focus", html: true });
}
I then hook up a databound event to the grid to then attach the event features to the "pop up" in my sample
Also note I have hooked in the bootstrap features just to make things a little easier for the demo. So this is using their popover feature. You could modify this code to work with your window.
Any issues let me know.
This is the kendo grid code
{ field: "marks", title: "marks",width: "160px",
template: function(dataItem) {
var marks = dataItem.marks;
var retString = '';
if(marks !== null && marks !== undefined)
{
if(marks.length > 40)
{
marks1 = marks.substring(0, 40)+'...';
retString1 ='<span>'+ marks1 +'</span>';
retString = retString1 + ' <button id="marksButton" type="button"' +
'data-toggle="popover" data-placement="auto right" data-container="body" ' +
'data-content="' + kendo.htmlEncode(addlRemarks) + '"' +
'data-title="marks" data-trigger="click" data-role-me="content-popover" > marks</button>';
}
else
{
retString = '<span>' + marks + '</span>';
}
}else
{
retString = '<span> - </span>';
}
return retString;
}
And its being called from a HTMl
<div class="panel-body" ng-show="accOpen[$index]">
<!-- Marks TABLE -->
<div marks-table=""
accordion-flag="accOpen[$index]"
name="name"
id="id"
>
</div>
</div>

Angular Kendo tabStrip - dynamic content and auto-select first tab

Using the Kendo UI tabStrip widget, I'd like to do two things:
1) auto-select the first tab, as it does not show the tab content right away.
2) Swap out the contentUrl of the first tab, under a specific condition of course.
Funny thing is, when I use the k-content-urls directive on my Html, the first tabs loads up the content right away.
ex/
<div kendo-tab-strip k-content-urls="['myTemplate.html', 'myTemplate2.html']">
However, I don't want to do it this way. I prefer the approach below, as in k-options="settings.tabOptions"
Here are the tabOptions in my controller code, and the HTML markup below it:
settings.tabOptions = {
animation: { open: { effects: "fadeIn" } },
select: function (e) {
console.log("Selected: " + e.item.innerText);
// NOT WORKING..
e.sender.dataSource.options.data[0].contentUrl = "../myNewTemplate.html"
},
change: function (e) {
console.log("Changed: ");
},
activate: function (e) {
console.log("Activated: " + e.item.innerText);
},
show: function (e) {
console.log("Shown: " + e.item.innerText);
},
contentLoad: function (e) {
console.log("Content loaded in " + e.item.innerText);
},
dataTextField: "title",
dataContentUrlField: "contentUrl",
dataSource: [{
title: "Formatting",
contentUrl: '../app/shared/include/grid-config/gad-config-grid-prop.html'
},
{
title: "Dimensions",
contentUrl: '../app/shared/include/grid-config/gad-config-grid-dimen.html'
},
{
title: "Risk Measures",
contentUrl: '../app/shared/include/grid-config/gad-config-grid-riskmeasures.html'
}],
error: function (e) {
console.log("Loading failed with " + e.xhr.statusText + " " + e.xhr.status);
}
};
<div id="Gadgettabs" kendo-tab-strip="tabstrip" k-options="settings.tabOptions">
<ul>
<li class="k-state-active">Formatting</li>
<li>Dimensions</li>
<li>Risk Measures</li>
</ul>
</div>
Again, I need to immediately show the first tab's content; and also figure out how to dynamically change out the content of the first tab.
Thanks in advance...
Bob
**** UPDATE ****
I'm trying to dynamically change the contentUrl in the select: event above but it's not working.
Final resolution:
note: if you not using "controller as" syntax in your ng-controller directive (as I am), then just replace my "settings." object with "$scope." in the controller code. And of course in the html, just remove "settings." .
// KENDO TABSTRIP
settings.urls = ['../app/shared/include/grid-config/gad-config-grid-prop.html', '../app/shared/include/grid-config/gad-config-grid-dimen.html', '../app/shared/include/grid-config/gad-config-grid-riskmeasures.html'];
if ($scope.widget.gadgetType == "chart") {
settings.urls[0] = '../app/shared/include/barchart-config/gad-config-barchart-prop.html';
};
settings.tabOptions = {
//animation: { open: { effects: "fadeIn" } },
select: function (e) {
console.log("Selected: " + e.item.innerText);
},
change: function (e) {
console.log("Changed: ");
},
activate: function (e) {
console.log("Activated: " + e.item.innerText);
},
show: function (e) {
console.log("Shown: " + e.item.innerText);
},
contentLoad: function (e) {
console.log("Content loaded in " + e.item.innerText);
},
error: function (e) {
console.log("Loading failed with " + e.xhr.statusText + " " + e.xhr.status);
}
};
<div id="Gadgettabs" kendo-tab-strip="settings.tabStrip"
k-rebind="settings.urls"
k-content-urls="settings.urls"
k-options="settings.tabOptions" >
<ul>
<li class="k-state-active">TAB1</li>
<li>TAB2</li>
<li>TAB3</li>
</ul>
</div>

How to programatically expand a node of Kendo treeview

I have a Kendo treeview that is built as below codes (see below). Each tree node has a unique data id field (that is employee Id).
I would like to have a text box ( <input type="text" ... /> ) and a button ( <input type="button" ... /> ) so user can input some id and when she hit the button, the button click event handler will let the treeview expand the node whose id matches the input id. How can I do that? Thank you very much.
Details of click event handler or the button:
function buttonExpand_onClick()
{
var id = $("textboxEmployeeId").val();
// ???
// how can I do the following code lines to expand the node with id of "id" to see all its children?
}
Details of the existing Kendo treeview building codes:
<div id="treeviewEmployee">
</div>
<script id="treeview-template" type="text/kendo-ui-template">
#: item.text #
</script>
$(function(
{
var defaultRootSelectedId = 1; // 1 is employee id of the root employee on first loading
$.ajax({
url: '/Employee/AjaxGetEmployeeNodes/?id=' + defaultRootSelectedId,
type: 'GET',
dataType: 'json',
async: false,
success: function (data, textStatus, xhr) {
$("#reeviewEmployee").kendoTreeView({
template: kendo.template($("#treeview-template").html()),
dataSource: data,
select: treeview_onSelect
});
_treeview = $("#treeviewEmployee").data("kendoTreeView");
},
error:
function (xhr, textStatus, errorThrown) {
alert(textStatus);
}
});
});
You can access the datasource on the treeview and find the node by id. I would also like to add that the treeView has a 'findByText()' method as well, in case that is what you want.
HTML
<script id="treeTemplate" type="text/x-kendo-template">
#: item.text #
</script>
<div id="content">
<div id="form">
<label>Node ID:
<input id="nodeId" type="text"/>
</label>
<button id="expandNodeBtn">Expand Node</button>
</div>
<h2>TreeView</h2>
<div id="treeView"/>
</div>
JAVASCRIPT
(function ($) {
$(document).ready(function () {
$("#treeView").kendoTreeView({
dataSource: [
{
text: 'one with id 1',
id: 1,
items: [
{
text: 'one-child-1',
id: 2
},
{
text: 'one-child-2',
id: 3
}
]
},
{
text: 'two with id 4',
id: 4,
items: [
{
text: 'two-child-1',
id: 5
},
{
text: 'two-child-2',
id: 6
}
]
}
]
});
$("#expandNodeBtn").on("click", function(e) {
var val = $("#nodeId").val();
console.log('val: ' + val);
var treeView = $("#treeView").data('kendoTreeView');
var dataSource = treeView.dataSource;
var dataItem = dataSource.get(val); // find item with id = 5
var node = treeView.findByUid(dataItem.uid);
treeView.expand(node);
});
});
})(jQuery);
JSFiddle
I also put together a JSFiddle sample for you to play with: http://jsfiddle.net/jsonsee/D35Q6/
Slightly related, but I came here looking for an answer to this question: How to expand the whole branch when clicking to a parent node in angular treeview? Since I didnt find any answers, I post my solution here. Hope it helps someone.
html
<div id="treeview" kendo-tree-view="tree" k-options="options" k-on-change="selectItem(dataItem)">
</div>
controller
$scope.options = {
dataSource: dummyData,
template: $scope.treeItemTemplate
}
$scope.treeItemTemplate = "<button ng-click='expandRoot(dataItem)'>Blow up</button>";
$scope.expandRoot = function expandRoot(dataItem) {
dataItem.expanded = true;
if (dataItem.hasChildren) {
dataItem.load()
var children = dataItem.children.data();
children.forEach(function (c) {
c.expanded = true;
$scope.expandRoot(c)
});
}
}

Cannot set model MVC property

I am trying to set a Profile Property (ComplexID) through the standard Account controller code that comes with the standard MVC3 template. I am using a autocomplete widget from the jquery library to set the value of a hidden field when a value is selected from the autocomplete. The setter is confirmed by an alert I added, but when I try to save the textbox values, I get an error from the Model.IsValid saying the the ComplexID needs to be set. In the Account Model, I have set the ComplexID field as [Required]. What am I doing wrong? Thanks
<div>
<input type="text" name="q" id="complexes" />
#Html.HiddenFor(m => m.ComplexID, new { id="complexid"})
</div>
and the Jscript is:
$("#complexes").autocomplete({
source: function(request, response) {
$.ajax({
url: "/Account/QuickSearch", type: "POST", dataType: "json",
data: { query: request.term },
success: function(data) {
response($.map(data, function(item) {
return { label: item.Name + " , " + item.Address1, value: item.Name, id: item.ComplexID };
}))
}
})
},
minLength: 3,
select: function(event, ui) {
var selecteditem = ui.item;
$("#complexid").text(selecteditem.id);
alert(ui.item ? ("You picked '" + selecteditem.label + "' and the hidden textbox now has a value of " + $("#complexid").text()) : "Nothing selected");
}
});
Change this:
$("#complexid").text(selecteditem.id);
on
$("#complexid").val(selecteditem.id);

Resources