Disabling KendoUI drop down list options - html

How to disable an option of a kendoiu drop down list?
I couldn't find how to accomplish this in their documentation...

Try the following approach (here and here there are some demos): use a template for your items, which conditionally adds a class to the items to be disabled. The info about which items should be disabled comes from the underlying data objects.
HTML:
<script id="template" type="text/x-kendo-tmpl">
#
if (data.disabled != null) {#
<span class="tbd" > ${data.text} - is disabled </span>
# } else { #
<span>${data.text}</span > #
}#
</script>
<input id="color" value="1" />
jQuery and Kendo UI (note here the disabled extra property for the Orange item and the usage of the dataBound event):
var data = [{
text: "Black",
value: "1"
}, {
text: "Orange",
value: "2",
disabled: "disabled"
}, {
text: "Grey",
value: "3"
}];
$("#color").kendoDropDownList({
dataTextField: "text",
dataValueField: "value",
dataSource: data,
index: 0,
template: kendo.template($("#template").html()),
dataBound: function (e) {
$(".tbd").parent().click(false);
}
});
CSS for graying out:
.tbd{
color:#777777
}

While the accepted answer will prevent a click on the item, it still allows keyboard navigation (and feels pretty hackish).
Using the DataItems to identify which item should be disabled is indeed the way to go, but instead of removing the click handler, it is simpler to implement a Select handler that will stops the chain. This method is supported and documented by Kendo :
Fired when an item from the popup is selected by the user either with
mouse/tap or with keyboard navigation.
...
e.preventDefault Function
If invoked prevents the select action. The widget will retain the
previous selected item.
All that remains is to detect if we want to cancel the selection or not, which is trivial if your data item keeps a property that identifies whether it is available or not :
function Select(e) {
if (e.sender.dataItem(e.item).disabled) {
e.preventDefault();
}
}
Using a template to inject a specific class is not needed, but I would still recommend it if only to enable a proper styling.

Based on the question here, you could access the relevant item and change attributes like so:
var ds = $('#YourCombo').data().kendoComboBox.dataSource;
//someIndex is the index of the item in the dataSource
ds.data()[someIndex].set("enabled","False");

Kendo currently doesn't support such functionality but this is easiest hack I found to disable an option in Kendo Dropdown.
$("#" + id + "_listbox .k-item")[index].disabled = true;
where id -> ID of your dropdown
index -> position of the element in the dropdown you want to disable.
Hope it helps. Enjoy :)

You could try something like this:
var dropDown = $("#yourDropdown").data("kendoDropDownList");
dropDown.enable(false);
Try other way for specific index
var dropDown = $("#color").data("kendoDropDownList");
$("#color" + "_listbox .k-item")[index].disabled = true;
$("#color" + "_listbox .k-item").eq(index).addClass("tbd");
Fiddler for reference :- http://jsfiddle.net/xLs4n9dm/2/

If you want to disable the entire control and you are using the MVC fluent API, then you can use the .HtmlAttributes() method:
#Html.Kendo()
.DropDownList()
.HtmlAttributes(new { #disabled = "disabled" })

Try like this
$('#YourDropDown').attr('disabled', 'disabled');

Related

Conditionally adding tags options parameter to select2

I have multiple elements on a page that are triggering a load of select2 to the element. I'm trying to conditionally check if the element has a certain class, and if so add the tag option; otherwise do not. I thought something like this would work, but it's not:
$('.element_to_add_select_two_on').select2({
tags:function(element) {
return (element.className === 'classname_i_am_targeting');
},
});
What am I missing here? I'm subjecting myself to the following buffoonery to get this to target and load:
$('.element_to_add_select_two_on').each((index,element) => {
let showTags = false;
if ($(element).attr('class').split(' ').includes('classname_i_am_targeting')) {
showTags = true;
}
$(element).select2({
tags:showTags,
});
});
There are a few problems with your first attempt. First, you are defining tags as a function when what you want is the result of the function, since tags needs to be defined as a boolean true or false. The other is that inside your .select2() call, you do not have access to the calling element $('.element_to_add_select_two_on') in the way that you think. It isn't an event that you are listening on, it's a function call that wants an object passed with its configuration.
You conveyed that your second method works, but it can be simplified with the jQuery hasClass() function:
$('.element_to_add_select_two_on').each((index, element) => {
$(element).select2({
tags: $(element).hasClass('classname_i_am_targeting'),
});
});
There is a much simpler way to do all of this, however, and it is much more flexible and already built into select2 via the way of data-* attributes (note, you need jQuery > 1.x). You can simply add data-tags="true" to any of your select elements with which you want tags enabled. These will override any configuration options used when initializing select2 as well as any defaults:
<select data-tags="true">
...
</select>

Enable tab in AngularJS

In HTML disabled two tabs by default
"<tab heading='Test Case Details' active='tabs[1].active' disable='true'>"+
"<tab heading='Test Case Past Results' active='tabs[2].active' disable='true'>"+
When clicking on a function, both the tabs should be enabled and one to be active
$scope.tabs[2].active = true;
$scope.tabs[1].disabled = false;
The controller used is
$scope.tabs = [{ title:'Detailed Test Case 1', content:'Test case content details will come here', disabled: true }];
Still, the tab is not getting enabled. Anything else to be done in this.
You defined the disable attribute of both your tab on true and you never change that, so whatever you do, your tabs will always by disabled. I guess you should bind them to tabs[x].disabled and your function should do something like:
$scope.tabs[0].disabled = false;
$scope.tabs[1].disabled = false;
$scope.tabs[0].active = true;
To enable both tabs, then activate the first one.
Moreover, you should check your indexes and your array. You seem to have only one item in your array but you use the index "2" and you don't seem to be using the "0" index..
If you can use jQuery, you could assign each of the tabs an id and have the jQuery in your function to do something along the lines of:
$("#tab1").attr("disable","false");
$("#tab2").attr({"disable": "false", "active": "true");

Material Design - stepper how to remove/disable steps?

I'm using Material - Angular2 Stepper, and I have additional steps that I want to add/enable depending on what the user selects in the first step.
I tried the following:
- Load the additional forms into an array,
- then loop through it in the template with *ngFor
<mat-vertical-stepper linear>
<mat-step [stepControl]="firstForm" label="First">
<!-- Some form controls -->
</mat-step>
<mat-step *ngFor="let f of additionalForms" [stepControl]="f.form"
[label]="f.label">
<!-- Additional Steps -->
</mat-step>
</mat-vertical-stepper>
This works well for adding new steps, the problem is I can't remove them. If the user happened to come back to first form, and uncheck something, these additional steps wouldn't be required.
So trying something like: this.additionalForms = [] doesn't remove the steps. (until you click on one of the "removed" steps, then it throws an error: Cannot read property 'editable' of undefined, and only then, they're removed visually)
I also tried doing ChangeDetectorRef.detectChanges()
and tried wrapping into the NgZone.run()
but made no difference
Any solutions for this?
So I managed with this work-around:
https://github.com/angular/material2/issues/7700#issuecomment-336138411
1) Make a reference to the stepper:
<mat-vertical-stepper #stepper></mat-vertical-stepper>
2) Then, on the .ts side:
import { ViewChild } from '#angular/core';
import { MatVerticalStepper } from '#angular/material';
#ViewChild('stepper') stepper: MatVerticalStepper;
clearAdditionalForms(): void {
this.inventoryForms = [];
this.stepper._stateChanged(); // <- this : Marks the component to be change detected.
}
This is calling a private method which is probably a really bad idea, so if you have a better/correct solution, let me know, and I'll change the answer
A slightly more angular way, avoiding the private method way is to record what you need to do on the form control used by the step. So for instance let's say we have a step:
<mat-step [stepControl]="secondFormGroup">
<form [formGroup]="secondFormGroup">
<!-- your controls here -->
</form>
</mat-step>
Then define your form group:
this.secondFormGroup = this._formBuilder.group({
check: [false, Validators.requiredTrue]
});
We have now defined a pseudo element "check", that will be validated by the step.
Let's say we set something with a click function:
doClick(item) {
this.secondFormGroup.controls.check.setValue(item === 'thevalue');
}
Angular material will now do the rest, you will not be able to move past the step until item === thevalue.
Add *ngIf in each step
<mat-step *ngIf="*expression*"></mat-step>
Also, If you want to do not return the privously, you can use stepper's editable property as below
<mat-vertical-stepper linear>
<mat-step [stepControl]="firstForm" label="First" [editable]="false">
<!-- Some form controls -->
</mat-step>
<mat-step *ngFor="let f of additionalForms" [stepControl]="f.form"
[label]="f.label">
<!-- Additional Steps -->
</mat-step>
</mat-vertical-stepper>
based on https://material.angular.io/components/stepper/overview#editable-step
Angular Material 8.2.3
Best would be a [disabled] option, but incredibly they didn't add! So I tried all and I ended up a clean way to customize the step-headers:
To show/hide a step of course simply use *ngIf (what else?).
To disable steps dynamically based on user clicks / state of the store:
With great results: no hover background effect, cursor is normal, single step-header unclickable, still looks with full color: not opaque.
steps: Array<HTMLElement> = [];
subscriptions: Array<Subscription> = [];
ngAfterViewInit() {
// Needs continuous monitoring
this.subscriptions.push(
this.<observable>.pipe(
tap((data: Data) => {
// IMPORTANT: If you have an *ngIf on the steps,
// you have to sync the references of the HTML elements
this.syncHTMLSteps();
this.updateStepState(1, false); // Always disabled
if (data.isXXX) {
this.updateStepState(5, false);
} else if (data.isYYY) {
this.updateStepState(2, false);
this.updateStepState(5, true);
}
})
).subscribe());
}
ngOnDestroy() {
this.subscriptions.forEach((subscription) => {
if (subscription) {
subscription.unsubscribe();
}
});
}
/**
* Reads from the Dom the list of HTML elements for the steps.
*/
private syncHTMLSteps() {
this.steps = [];
let increment = 1;
let stepper: HTMLElement = document.querySelector('.mat-stepper-vertical');
if (!stepper) {
increment = 2; // 2, because Angular adds 2 elements for each horizontal step
stepper = document.querySelector('.mat-horizontal-stepper-header-container');
}
for (let i = 0; i < stepper.children.length; i += increment) {
this.steps.push(stepper.children[i] as HTMLElement);
}
}
/**
* Enable/Disable the click on the step header.
*
* #param step The step number (starts from 1)
* #param enabled The new state
*/
private updateStepState(step: number, enabled: boolean) {
// If you prefer to start using step 0, remove -1 here
this.steps[step - 1].style.pointerEvents = enabled ? '' : 'none';
}

Adding properties for a Polymer element to observe based on content or a better way to handle forms

I need to create a form using the Polymer Paper-Input elements, and I need a way to know when all required content has been filled out.
I looked for a built in element, but didn't see one. So I wanted to create a polymer form element that would wrap all of the input tags. The resulting element would have an Invalid attribute which lets you know if any of the input tags are invalid.
The use of the tag would look like this:
<test-form id="testform">
<paper-input label="test" required error="This field is required"></paper-input>
</test-form>
Invalid: {{ $.testform.invalid }}
However, it appears that by the time in the elements lifecycle that I can loop over all the elements inside of the content tag, that anything added to the observe object is ignored.
Here is the code I was working on below:
<polymer-element name="test-form" attributes="invalid">
<template>
<content id="content">
</content>
</template>
<script>
Polymer('test-form', {
domReady: function () {
this.observe = {};
for (var i = 0; i < this.children.length; i++) {
this.observe["this.children[" + i + "].invalid"] = "valChanged";
}
},
invalid: false,
valChanged: function (oldValue, newValue) {
// TODO: If newValue is true set invalid to true
// If newValue is false, loop over all elements to see if all are now valid and invalid can be set to false.
alert("VALUE CHANGED" + oldValue + newValue);
}
});
</script>
Is there a better way to handle this or does anyone know how to make changes to what polymer is observing at this point in the lifecycle?
As far as checking the form's validity, you could simply check each form element's invalid property:
validate: function() {
var invalid = false;
Array.prototype.forEach.call(this.children, function(child) {
if (child.invalid === true) {
invalid = true;
}
});
this.invalid = invalid;
}
Then you could add an input event listener and run this method each time a form element's input changes.
Here's a working jsbin.
If I understand your question, your high level goal is form validation?
As has been detailed in polycasts and other places, I have used iron-form which has some very powerful validate() functionality, including what you mention above and much more.
It does sometimes require some odd usages of hidden <input> fields to get all of the work done, but this is easy to learn in the polycasts, such as polycast 55 and 56
If you stumbled upon this question in 2017, you would definitely now want to use more primitive tech, after you've seen what this has to offer.

ExtJs 4.1 cross browser issue(combo box in header not working)

Following code create grid column with combo box in header but only working in IE for other browser combo box is not click able.
columns : [ {
header : 'Selected Year<br/><select style="width:80px" id="mndyearlist"</select>',menuDisabled : true,width:100}]
Thanks
Click on header has handler attached, and each click is bubbling up from select. Additionaly there is also drag&drop attached by default, which doesn't help either. So, you should change that behaviour. You can for example extend Column like so:
Ext.define('Ext.grid.column.SelectColumn', {
extend: 'Ext.grid.column.Column',
alias: 'widget.selectcolumn',
// disable D&D
draggable: false,
// handle click event
onElClick: function(e, t) {
var target = e.getTarget('select');
// if event is from select supress default behaviour
if (!target) {
return this.callParent(arguments);
}
}
});
Then just use that column in your grid, and your select should work.
Working sample: http://jsfiddle.net/9aTUY/4/