This is very simple, I have a Multiselect and when one item is selected, I want the tag to represent the DataTextField. When multiple items are selected, I want one tag to represent the quantity of items selected. Here is my code:
#(Html.Kendo().MultiSelect()
.Placeholder("Select Employees...")
.Name("empSelect")
.DataTextField("Employee")
.DataValueField("PERSONNEL_KEY")
.HtmlAttributes(new { style = "width:100%;font-size:10px;", id = "empSelect" })
.AutoBind(false)
.AutoClose(false)
.Filter(FilterType.Contains)
.TagTemplateId("tagTemplate")
.DataSource(source => {
source.Read(read =>
{
read.Action("GetEmployees", "EmployeeTS");
})
.ServerFiltering(true);}))
and here is the tagTemplate script:
<script id="tagTemplate" type="text/x-kendo-template">
# if (data.length < 2) { #
<span>
#= data.Employee #
</span>
# } else { #
<span>
#= data.length # selected
</span>
# } #
All items come back from my Controller just fine. When I select an item(s), the tag displays "UNDEFINED selected". Apparently "data.length" is undefined, yet I know of no other way to grab the count of items selected.
I am currently on the 2016.3.1118 build of Telerik Kendo MVC.
"data" doesn't have property of length. Because of that, always works "else" and shows undefined.
<script>
function onChange(e) {
var multi = $("#empSelect").data("kendoMultiSelect");
var multi = $("#empSelect").data("kendoMultiSelect");
if (multi.listView._dataItems.length > 1) {
multi.setOptions({
tagMode: 'single'
});
} else {
multi.setOptions({
tagMode: 'multiple'
});
}
multi.refresh();
}
#(Html.Kendo().MultiSelect()
.Placeholder("Select Employees...")
.Name("empSelect")
.DataTextField("TANIM")
.DataValueField("URETIM_YERI")
.AutoBind(false)
.AutoClose(false)
.Filter(FilterType.Contains)
.TagMode(TagMode.Multiple)
.Events(e =>
{
e.Change("onChange");
})
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetFactories", "Factory");
})
.ServerFiltering(true);
}))
Related
I'm trying to test my component that has the following conditional rendering:
const MyComponent = () => {
const [isVisible, setIsVisible] = (false);
if(selectedOption == 'optionOne')
setIsVisible(true);
else
setIsVisible(false);
return (
<div>
<Select data-testid="select1" selectedOption={selectedOption} />
{isVisible ? <Select data-testid="select2" selectedOption={anotherSelectedOption} /> : null }
</div>
)}
If selectedOption in select1 is 'optionOne', then select2 shows up.
Here is how I am testing it:
describe('Testing', () => {
let container: ElementWrapper<HTMLElement>;
const testState = {
userChoice1: {
selectedOption: ['optionOne'],
},
userChoice2: {
selectedOption: ['test1', 'test2'],
},
} as AppState;
beforeEach(() => {
container = render(<MyComponent/>, testState);
});
it('should show select2 if optionOne is selected', async () => {
const { getByTestId, getAllByTestId } = render(<MyComponent/>);
expect(container.find('span').getElement().textContent).toBe("optionOne"); // this successfully finds select1 with optionOne selected, all good
await screen.findAllByTestId('select2')
expect(screen.getAllByTestId('select2')).toBeInTheDocument();
});
In the testing above, as select1 has optionOne selected, I expect to select2 to show up. However, I am getting an error Unable to find an element by: [data-testid="select2"]. It also returns the whole HTML body, where I see select1 element with optionOne selected, but no select2 at all as it seems to still be hidden.
What am I missing here? How can I unhide select2 within the unit test?
in my form there are asp kendo multiselect ; I want select some items from multiselect per selected value from a asp kendo dropdownlist? how can I do this ?
#(Html.Kendo().DropDownList()
.Name("dropdown")
.Filter("contains")
.DataTextField("Name")
.DataValueField("Id")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("action", "controller" });
});
})
.AutoBind(true)
)
#(Html.Kendo().MultiSelect()
.Name("multiselect")
.Filter("contains")
.HtmlAttributes(new { style = "width:100%" })
.DataTextField("Name")
.DataValueField("Id")
.Filter("contains").Animation(false)
.DataSource(source =>
{
source.Read(read =>
{
read.Action("action", "controller" });
});
})
)
i solved this problem;
first define a function for dropdown_change and in that function get selected value from dropdown and load data by jquery ajax then select items from multiselect :)
$(document).ready(function () {
$('#dropdownName').data("kendoDropDownList").bind("change", drp_change);
});
function drp_change() {
var selected = $('#dropdownName').val();
if (selected > 0) {
//fill multiselect per selected value
var params= { [paramName]: selected };
$.get('/controller/action', params, function (data) {
var multiSelect = $("#multiselectName").data("kendoMultiSelect");
var selected = $.map(data, function (item) {
return item;
});
multiSelect.value(selected);
multiSelect.trigger("change");
})
} else {
$('#multiselectContailner').hide();
}
}
I'm trying to take a user inputted code and compare it to code within my database. Right now I can bring the code and display it outside the map function but when I try to add it, it doesn't work. here is my database:
[
{
"dwelling_code": "ABC-XYZ",
"dwelling_name": "Neves Abode",
"has_superAdmin": true,
"room": []
}
This is the parent component:
class Dwel2 extends Component {
state = {
house: [],
selectedMovie: null,
data: "ABC-XYZ"
}
componentDidMount() {
fetch('Removed for question', {
method: 'GET',
headers: {
}
}).then(resp => resp.json())
.then(resp => this.setState({ house: resp }))
.catch(error => console.log(error))
}
houseClicked = h => {
console.log(h)
}
render() {
return <div>
<EnterCode dataFromParent={this.state.data}
house={this.state.house}
houseClicked={this.house} />
</div>
}
}
This is the child component:
function EnterCode(props) {
return (
<div>
<div>
*THIS BIT DISPLAYS THE CODE*{props.dataFromParent}
</div>
{props.house.map(house => {
var test = house.dwelling_name
var code = house.dwelling_code
if (code === {props.dataFromParent}) {
test = "Test"
}
return (
<React.Fragment>
<div>{test}</div>
</React.Fragment>
)
})}
</div>
)
}
I just want to compare the code in the database to the code defined in the parent component. Here is the error that's coming up this is in the child component.
Line 17:31: 'dataFromParent' is not defined no-undef
You made a tiny mistake in the if statement. You put the props.dataFromParent in brackets, which in the context of JSX would be required, but in the context of JS means creating an object, which is clearly wrong.
if (code === props.dataFromParent) {
test = "Test"
}
Hope this helps :)
I'm using Telerik for MVC and trying to get the multi-select to populate with the initial values in an Edit scenario.
<script>
function filterProducts() {
return {
manufacturerId: $("#ServiceBulletinItem_ManufacturerId").val()
};
}
function onManufacturerChange(e) {
var v = e.sender.dataItem().Value;
$.post("#Url.Action("GetCascadeProducts", "Components")", { manufacturerId: v }, function (result) {
var grid = $("#ServiceBulletinItem_ApplicableProducts").data("kendoMultiSelect")
grid.setDataSource(result)
});
}
function InitialPopulate(manId) {
$.post("#Url.Action("GetCascadeProducts", "Components")", { manufacturerId: manId }, function (result) {
var grid = $("#ServiceBulletinItem_ApplicableProducts").data("kendoMultiSelect")
grid.setDataSource(result)
});
}
$(document).ready(function () {
$('.control-datepicker').Zebra_DatePicker();
var m = $("#ServiceBulletinItem_ManufacturerId").val();
InitialPopulate(m);
});
</script>
<div class="form-group">
#Html.LabelFor(m => m.ManufacturerList, "Manufacturer", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#(Html.Kendo().DropDownListFor(m => m.ServiceBulletinItem.ManufacturerId)
.HtmlAttributes(new { #class = "col-md-6 form-control" })
.Filter("contains")
.DataValueField("Value")
.DataTextField("Text")
.BindTo((IEnumerable<SelectListItem>)Model.ManufacturerSelectList)
.HtmlAttributes(new { style = "width:70%;" }).Events(e =>
{
e.Change("onManufacturerChange");
})
)
</div >
</div >
<div class="form-group">
#Html.LabelFor(m => m.ProductList, "Product", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#(Html.Kendo().MultiSelectFor(m => m.ServiceBulletinItem.ApplicableProducts)
.AutoClose(false)
.DataTextField("ProductName")
.DataValueField("ProductId")
.Placeholder("Select products...")
)
</div>
</div>
I'm trying to populate the manufacturer drop down and the Product multiSelect. The ApplicableProducts item is an IEnumerable representing the ProductId's of all those previously selected and I know that when I select the manufacturer and it calls the GetCascadeProducts controller method it will return back a collection of ProductId and ProductName for all the manufacturers products of which those productId is the ApplicableProducts property should exist.
On document.ready I can call the InitialPopulate method with the manufacturerID which will populate the multiSelect items but can't seem to populate the initial values.
I couldnt get the binding working correctly so ended up using
#(Html.Kendo().MultiSelect()
.Name("ServiceBulletinItem_ApplicableProducts")
.AutoClose(false)
.DataTextField("ProductName")
.DataValueField("ProductId")
.Placeholder("Select products 2...")
.AutoBind(false)
)
and then on the using the following code on document ready to make an ajax call to populate the manufacturer and product controls
function PopulateProductsInitial(manId) {
$.post("#Url.Action("GetCascadeProducts", "Components")", { manufacturerId: manId }, function (result) {
var grid = $("#ServiceBulletinItem_ApplicableProducts").data("kendoMultiSelect")
grid.setDataSource(result);
var s = $("#ServiceBulletinItem_Id").val();
$.post("#Url.Action("GetSBProducts", "ServiceBulletins")", { Id: s}, function (result) {
var arr = [];
result.forEach(function (element) {
arr.push(element.ProductId);
});
var grid = $("#ServiceBulletinItem_ApplicableProducts").data("kendoMultiSelect")
grid.value(arr);
});
});
}
}
$(document).ready(function () {
//Populate Initial Values
PopulateProductsInitial($("#ServiceBulletinItem_ManufacturerId").val());
$('#YourButton').click(SendForm);
});
The problem then became sending the selected items back to the controller when the edit was complete which again seemed convoluted because the control was not bound and therefore I had to make an Ajax call to submit the data.
function SendForm() {
var items = $("#ServiceBulletinItem_ApplicableProducts").data("kendoMultiSelect").value();
//Manipulate into ServiceBulletinViewModel for the save
var data = {
Id: $("#ServiceBulletinItem_Id").val(),
ServiceBulletinItem: {
Id: $("#ServiceBulletinItem_Id").val(),
ManufacturerId: $("#ServiceBulletinItem_ManufacturerId").val(),
IssueDate: $('#ServiceBulletinItem_IssueDate').val(),
Heading: $('#ServiceBulletinItem_Heading').val(),
Details: $('#ServiceBulletinItem_Details').val(),
Url: $('#ServiceBulletinItem_Url').val(),
SelectedProducts: items
}
}
$.ajax({
type: 'POST',
url: '/ServiceBulletins/Edit',
contentType: 'application/json',
data: JSON.stringify(data),
success: function (result) {
//Your success code here..
if (result.redirectUrl != null) {
window.location = result.redirectUrl;
}
},
error: function (jqXHR) {
if (jqXHR.status === 200) {
alert("Value Not found");
}
}
});
}
It all seemed a lot more convoluted than any of the demo's that teleriks and I couldnt find any good examples of binding from remote sources which looked similar.
As the binding is convention based I'm wondering if its possible to simplify the ajax calling for the post functionality with the correct naming of the controls so that I can simply get the selected items on the multiselect control or if the ajax post is the way to go.
Is it possible to use a Modal without a trigger? I will open and close it via state.
For example, I want to use onClick on an input field(with a file name) to open the modal with a file chooser and then edit the name of the choosen file in the input field. All this in a nested modal...
Looks much simpler if I will have both modals in a parent component without the triggers, and I will display/hide them via open={true/false}
Thanks
Yes it is. Don't set the prop trigger (it is not required) and just provide the open value from state/props.
class container extends Component {
state = {
isParentOpen: false,
isChildOpen: false
}
handleClick = () => {
this.setState({
isParentOpen: !this.state.isOpen
});
}
handleFocus = () => {
this.setState({
isChildOpen: true
});
}
render() {
return (
<div>
<Modal
open={this.state.isParentOpen}
size="large"
>
...
<Input onFocus={this.handleFocus} />
</Modal>
<Modal
open={this.state.isChildOpen}
size="small"
>
...
</Modal>
<Button onClick={this.handleClick} />
</div>
);
}
}
(You can nest Modal if you want to)
Pass a prop to the modal component and fire handleOpen according to the prop on ComponentDidMount. This will allow the modal to be closed.
class ModalContainer extends Component {
componentDidMount() {
const { startOpen } = this.props;
if (startOpen) {
this.handleOpen();
}
}
handleOpen = () => this.setState({ modalOpen: true });
handleClose = () => this.setState({ modalOpen: false });
render() {
return (
<Modal open={this.state.modalOpen} onClose={this.handleClose} />
)
}