Kendo Dropdown sync not working inside Kendo Menu - kendo-ui

I am trying to use kendo dropdown inside a Kendo Menu. The dropdown is rendering fine. I have added noDatatemplate inside kendo dropdown to add new item to my datasource. But when i click on Add button, the newly added item is not showing inside the dropdown. When i try to console the dropdown datasource, i see the newly added item there. So, datasource.sync() is not rendering the newly added value in the dropdown.
If i use it this outside the kendo menu then it is working fine.
Please suggest what i can do to make it work.
Kendo Menu Html
var arr=[{destination:"ABC",destination:"XYZ"}];
$(window).on('load', function () {
$("#mainSapMenu").kendoMenu({
});});
function AddMenuClick() {
BindDestination();
}
function BindDestination(){
$("#drpSapDest").kendoDropDownList({
dataTextField: "destination",
dataValueField: "destination",
optionLabel: "--Select--",
filter: "startswith",
dataSource:arr,
noDataTemplate:$("#nodestinationTemplate").html(),
valuePrimitive: true,
});
}
function addNewItem(id, val) {
var widget = $("#" + id).getKendoDropDownList();
var datasource = widget.dataSource;
if (id == "drpSapDest") {
datasource.add({ "destination": val });
}``
datasource.one("sync", function () {
widget.select(dataSource.view().length - 1);
});
datasource.sync();
}
<script src="http://kendo.cdn.telerik.com/2021.1.119/js/kendo.all.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="mainSapMenu">
<li id="addNewMenuClick" onclick="AddMenuClick();">
Add
<ul>
<li>
<div id="searchTemplate" style="padding: 10px;">
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12">
<label class="col-md-3 col-lg-3 col-sm-3">Destination</label>:
<div class="col-lg-4 col-md-4 col-sm-4">
<input id="drpSapDest" class="selectpicker" />
<script id="nodestinationTemplate" type="text/x-kendo-tmpl">
<div>
No data found. Do you want to add , click below - '#: instance.filterInput.val() #' ?
</div>
<br />
<button class="k-button" style="background-color:\\#00547d;color:\\#fff" onclick="addNewItem('#: instance.element[0].id #', '#: instance.filterInput.val() #')">Add</button>
</script>
</div>
</div>
<div class="col-lg-12 col-md-12 col-sm-12 ">
<label class="col-md-3 col-lg-3 col-sm-3"></label>
<button class="btn blue-btn-small" onclick="CreateNewNode();"><i class="glyphicon glyphicon-plus"> </i> Add</button>
</div>
</div>
</div>
</li>
</ul>
</li>
<li id="searchMenuClick" onclick="RefreshMenuClick();">
Refresh
</li>
</ul>

Related

How to avoid redrawing entire tab every time in KnockoutJS?

In this very basic example using Bootstrap Tabs, every time I click on a tab, KnockoutJS redraw the entire tab, is there a way to "save" the state of the tab so next time I click on Messages, KO doesn't have to redraw the entire thing?
It takes ~100ms to draw. (According to Chromium profiler), fps drops to 1fps. It makes the whole thing very unresponsive.
<div>
<ul class="nav nav-tabs" role="tablist">
<li role="presentation">Profile</li>
<li role="presentation">Messages</li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="tab_storage" data-bind="with: BuildingsVM">
<h2 data-bind="i18next: 'AllOurStorage'"></h2>
<div class="row" data-bind="foreach: buildingsByType['RawStorage']">
<div data-bind="template: { name: 'tpl_building' }"></div>
</div>
<div class="row" data-bind="foreach: buildingsByType['RefinedStorage']">
<div data-bind="template: { name: 'tpl_building' }"></div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="messages" data-bind="messages">
<div data-bind="foreach: message">
<span data-bind="text: title"></span>
</div>
</div>
</div>
</div>
Is it possible to keep the state of the DOM so KO doesn't have to redraw the entire tab every time I click on it? (Or an alternative solution)
I'm using the following ko options to avoid unnecessary updates when I array.push(a_lot_of_things):
ko.options.deferUpdates = true;
ko.options.rateLimit = 25;
EDIT:
Tabs are switched using Bootstrap JS library.
$("#MenuTab").on('click','a', function(e) {
e.preventDefault();
var id = $(this).attr('href');
$(this).tab("show");
});
Template for a building 'card':
<script type="text/html" id="tpl_building">
<div class="col-xs-10 col-sm-6 col-md-3">
<div class="card card-raised">
<div class="card-header"><h3 data-bind="text: buildingName"></h3> </div>
<div class="card-content">
<div class="row" data-bind="if: (buildingType == 'RawStorage' || buildingType == 'RefinedStorage')">
<div class="col-xs-4">
Usage: <span data-bind="text: getOccupyingSpace"></span> / <span data-bind="text: TotalCapacity"></span>
</div>
<div class="col-xs-8">
<span data-bind="meter: {value: getOccupyingSpace, max: TotalCapacity}"></span>
</div>
</div>
<div class="row">
<!-- ko foreach: Ressources -->
<div class="col-md-6" data-bind="if: $parent.TotalCapacity">
<span data-bind="text: Name"></span> <span data-bind="text: Qte"></span> (<span class="small" data-bind="text: getOccupyingSpace"></span>)
<!-- ko if: ProductionRate() -->
<span data-bind="text: ProductionRate()"></span>/s
<!-- /ko -->
</div>
<div class="col-md-6" data-bind="if: ProductionRate">
<span data-bind="text: Name"></span> <span data-bind="text: getProductionRatePerSecond()"></span>/s (1 every <span data-bind="text: ProductionRate()/1000"></span> sec)
</div>
<!-- /ko -->
</div>
</div>
<div class="card-footer">
<!-- ko if: initialConstructionGoing -->
<i class="fa fa-exclamation-triangle icon-gradient-warning" class="ko-popover"
data-bind="popover: initialConstructionGoing, popoverOptions: { title: i18nextko.t('UnderConstruction_potitle') }" ></i>
<span data-bind="i18next: 'UnderConstruction'"></span> <span data-bind="text: getBuildProgress"></span>
<span data-bind="meter: {p: getBuildProgress, onComplete: 'remove'}"></span>
<span data-bind="WorkersAssigned().length"></span>/<span data-bind="WorkersBuild"></span>
<!-- /ko -->
</div>
</div>
</div>
</script>
Custom binding for 'meter' (A progress bar):
ko.bindingHandlers.meter = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
// This will be called when the binding is first applied to an element
// Set up any initial state, event handlers, etc. here
var progress = ko.unwrap(valueAccessor());
if(progress.value) {
var value = ko.unwrap(progress.value);
var max = ko.unwrap(progress.max);
if(value === 0 && max === 0) {
var percentage = 0;
} else {
var percentage = (value/max)*100;
}
} else {
var percentage = ko.unwrap(progress.p);
}
$progress_tpl = $('<div class="meter"><span style="width: '+percentage+'%"></span></div>');
if(progress.onComplete) {
$progress_tpl.attr('data-oncomplete', progress.onComplete);
}
$(element).append($progress_tpl);
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
// This will be called once when the binding is first applied to an element,
// and again whenever any observables/computeds that are accessed change
// Update the DOM element based on the supplied values here.
var progress = ko.unwrap(valueAccessor());
if(progress.value) {
var value = ko.unwrap(progress.value);
var max = ko.unwrap(progress.max);
var percentage = (value/max)*100;
} else {
var percentage = ko.unwrap(progress.p);
}
$(element).find('.meter span').stop().animate({'width': percentage+'%'}, (bindingContext.$root.cf.refreshEvery), 'swing', function() {
if(percentage >= 100) {
if($(element).find(".meter").attr('data-oncomplete') == 'remove') {
$(element).hide(300, function() {
$(element).remove();
ko.cleanNode(element);
});
} else if($(element).find(".meter").attr('data-oncomplete') == 'reset') {
$(element).hide(300, function() {
$(element).remove();
});
} else {
}
}
});
}
};
my KO main VM:
var mainVM = {
Ressources: new RessourcesVM(),
Buildings: new BuildingsVM(),
cf: {
...
}
}
Also modified original tab-content code to reflect the real code (using templates).
I would've made a JSfiddle but for some obscure reasons, it doesn't seem to work properly (new router firmware might be the issue, blocking CDN)à
For a better understanding cotext-wise, you can have a look at my other question: How can I optimize my KnockoutJS pureComputed function?
Looking at the DOM tree in the console, all the elements are still present, even if the tab is not active - maybe something else make the delay.

Ajax not triggering for Partial view

I am adding Partial view in to my main view , the partial view code snippet is:
<li class="item-#j deeper parent active">
<a class="" href="">
<span data-toggle="collapse" data-parent="#menu-group-1" href="#sub-item-#j" class="sign"><i class="icon-plus icon-white"></i></span>
<span class="lbl">Brands</span>
</a>
<ul class="children nav-child unstyled small collapse" id="sub-item-#j">
#foreach (var brand in Model.BrandList)
{
<li class="item-#j deeper parent active">
<div class="checkbox">
<label>
<input type="checkbox" value="#brand._id">
#*<a class="" href="#Url.Action("FilterData", "ShopWindow", new {shopKey=house._id,houseKey=house._id,houseName = house.House})">*#
<span class="lbl">#brand.Brand</span>
#*</a>*#
</label>
</div>
</li>
j++;
}
</ul>
</li>
in my main view I have a script to get all the check boxes that user have selected, the script snippet :
<script type="text/javascript">
var selectedBrand=[];
$("input[type='checkbox']").change(function () {
$('#brand input:checked').each(function () {
selectedBrand.push($(this).attr('value'));
alert("Test");
})
sendAjaxRequest();
});
When I select any check box from the partial view the script's change function is not getting triggered. This change function triggers if I check any checkbox in the main page but not for checkboxes belongs to partial view .
Any idea?
Thanks
I found the solution :
changed
$("input[type='checkbox']").change(function () {
to
$(document).on('change', '.checkbox', function() {

Kendo TabStrip and Kendo Templates

I have to load different KENDO templates dynamically on each tab click of Tabstrip . The datasource for all tabs are same . I am trying to do it as below but its not working . Please advise.(Kendo TabStrip and Kendo Templates)
<div class="tabs-details-wrapper" id="Tab1">
<ul>
<li class="k-state-active" >Identification</li>
<li>Planning</li>
<li>Implementation</li>
<li>Review</li>
<li>Management Response</li>
</ul>
<div>
<div class="row">
<div class="col-xs-12 col-md-5">
<div class="">
<div class="form-horizontal" ></div>
</div>
</div>
</div>
</div>
</div>
<script id="details-templateTab1" type="text/x-kendo-template">
<div class="form-group">
<label class="col-xs-12 col-md-4 control-label">Year of Completion</label>
<div class="col-xs-12 col-md-8">
<span class="control-readonly"></span>
</div>
</div>
<div class="form-group">
<label class="col-xs-12 col-md-4 control-label">Title</label>
<div class="col-xs-12 col-md-8">
<span class="control-readonly"></span>
</div>
</div>
</script>
<script id="details-templateTab2" type="text/x-kendo-template">
<div class="form-group">
<label class="col-xs-12 col-md-4 control-label">Hello1</label>
<div class="col-xs-12 col-md-8">
<span class="control-readonly">
</span>
</div>
</div>
<div class="form-group">
<label class="col-xs-12 col-md-4 control-label">Title1</label>
<div class="col-xs-12 col-md-8">
<span class="control-readonly">
</span>
</div>
</div>
</script>
$(".tabs-details-wrapper").kendoTabStrip({
select: function (e) {
//var data = this.dataSource.at($(e.item).index());
var templateSelector = ""
// alert(e);
if (e.item.innerText == "Identification") templateSelector = kendo.template($("#details-templateTab1").html())
else templateSelector = kendo.template($("#details-templateTab2").html()) ;
// alert(e.contentElement);
//templateSelector = kendo.template($("#details-templateTab1").html());
$(e.contentElement).html(templateSelector);
// kendo.bind(e.contentElement, data);
// $(e.contentElement).html(template(this.dataSource.at($(e.item.innerText).index())))
},
// template: $("#details-templateTab1"),
animation: false
//dataSource: ds
// dataSource: ds,
});
I have started a jsBin to assist with your issue. When I click each tab it loads content like you desribe. Do you have a datasource javascript object to add to your code?
Need more info, please.
$(".tabs-details-wrapper").kendoTabStrip({
select: function (e) {
//var data = this.dataSource.at($(e.item).index());
var templateSelector = ""
// alert(e);
if (e.item.innerText == "Identification") templateSelector = kendo.template($("#details-templateTab1").html())
else templateSelector = kendo.template($("#details-templateTab2").html()) ;
// alert(e.contentElement);
//templateSelector = kendo.template($("#details-templateTab1").html());
$(e.contentElement).html(templateSelector);
// kendo.bind(e.contentElement, data);
// $(e.contentElement).html(template(this.dataSource.at($(e.item.innerText).index())))
},
// template: $("#details-templateTab1"),
animation: false
//dataSource: ds // what is your DS?
// dataSource: ds,
});
I think the problem is that in your datasource you are not defining the "dataContentField". Once I added this in conjunction with a datasource I started seeing dynamic results from select function.
Here is my JavaScript
$(".tabs-details-wrapper").kendoTabStrip({
select: function (e) {
var templateSelector = ""
if (e.item.innerText == "Identification") templateSelector = kendo.template($("#details-templateTab1").html())
else templateSelector = kendo.template($("#details-templateTab2").html());
$(e.contentElement).html(templateSelector(this.dataSource.at($(e.item).index())))
},
animation: false,
dataTextField: "Name",
dataContentField: "Content",
dataSource: [
{ Name: "Identification", YearOfCompletion: "1998", Title: "This is first title", Content: "", customMessage: "This is custom message 1" },
{ Name: "Planning", YearOfCompletion: "1999", Title: "This is second title", Content: "", customMessage: "This is custom message 2" },
{ Name: "Implementation", YearOfCompletion: "2000", Title: "This is third title", Content: "", customMessage: "This is custom message 3" },
{ Name: "Review", YearOfCompletion: "2001", Title: "This is fourth title", Content: "", customMessage: "This is custom message 4" },
{ Name: "Management Response", YearOfCompletion: "2002", Title: "This is fifth title", Content: "", customMessage: "This is custom message 5" }
]
});
It didn't really matter what i put in the content property of the dataSource because this is getting replaced on select.
Here is my html
<div class="tabs-details-wrapper" id="Tab1"></div>
<script id="details-templateTab1" type="text/x-kendo-template">
<div class="form-group">
<label class="col-xs-12 col-md-4 control-label">Year of Completion</label>
<div class="col-xs-12 col-md-8">
<span class="control-readonly">#=YearOfCompletion#</span>
</div>
</div>
<div class="form-group">
<label class="col-xs-12 col-md-4 control-label">Title</label>
<div class="col-xs-12 col-md-8">
<span class="control-readonly">#=Title#</span>
</div>
</div>
</script>
<script id="details-templateTab2" type="text/x-kendo-template">
<div class="form-group">
<label class="col-xs-12 col-md-4 control-label">Hello1</label>
<div class="col-xs-12 col-md-8">
<span class="control-readonly">#=customMessage#</span>
</div>
</div>
<div class="form-group">
<label class="col-xs-12 col-md-4 control-label">Title1</label>
<div class="col-xs-12 col-md-8">
<span class="control-readonly">#=Title#</span>
</div>
</div>
</script>
Is this what your looking for?

How to define extra button in fine uploader template that will trigger its own end action

I want to have
- a text field and a button. Upon click of button text data will need to posted to endpoint.
The text field and button will repeat for each file in the uploader.
Below my attempt, and it is not working properly in all the cases and want to get to better solution.
The text field: qq-edit-caption
The button: qq-upload-update-caption
The button acts as delete button with selector 'qq-upload-delete-selector' and to differentiate I set a flag true on the onclick action (crappy I know!).
I read lot about creating 'extraButton' and all it talks about(as per my understanding) creating additional upload button, buy I need button on each file like DELETE and CANCEL,and not sure how I can cleanly implement the solution. Any help is much appreciated.
My template
<div class='qq-uploader-selector qq-uploader' qq-drop-area-text='Drop files here'>
<div class='qq-total-progress-bar-container-selector qq-total-progress-bar-container'>
<div role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100' class='qq-total-progress-bar-selector qq-progress-bar qq-total-progress-bar'></div>
</div>
<div class='qq-upload-drop-area-selector qq-upload-drop-area' qq-hide-dropzone>
<span class='qq-upload-drop-area-text-selector'></span>
</div>
<div class='buttons'>
<div class='qq-upload-button-selector qq-upload-button'>
<div>Select files</div>
</div>
<button type='button' id='trigger-upload-section<?php echo $ind; ?>' class='btn btn-primary file-section-button'>
<i class='icon-upload icon-white'></i> Upload
</button>
</div>
<span class='qq-drop-processing-selector qq-drop-processing'>
<span>Processing dropped files...</span>
<span class='qq-drop-processing-spinner-selector qq-drop-processing-spinner'></span>
</span>
<ul class='qq-upload-list-selector qq-upload-list' aria-live='polite' aria-relevant='additions removals'>
<li>
<div class='qq-progress-bar-container-selector'>
<div role='progressbar' aria-valuenow='0' aria-valuemin='0' aria-valuemax='100' class='qq-progress-bar-selector qq-progress-bar'></div>
</div>
<span class='qq-upload-spinner-selector qq-upload-spinner'></span>
<div class="filewrapper">
<div class="filecontainer">
<div class="filecontent">
<img class='qq-thumbnail-selector' qq-max-size='80' qq-server-scale>
</div>
<span class="qq-upload-file-selector qq-upload-file filename"></span>
</div>
<div class="filesidebar">
<!--span class='qq-upload-caption-selector qq-upload-caption'></span-->
<!--span class='qq-edit-caption-icon-selector qq-edit-caption-icon kk-editable' aria-label='Edit caption'></span-->
<input class='qq-edit-caption-selector qq-edit-caption kk-editing' placeholder='Enter Caption here ...' onchange='captionUpdate();'>
</div>
<div class="filesidebar2">
<button type='button' class='qq-btn qq-upload-delete-selector qq-upload-update-caption file-section-button btn-primary' onclick='captionUpdate(true);' title='Caption Update' disabled><i class='icon-pencil icon-white'></i></button>
<button type='button' class='qq-btn qq-upload-cancel-selector qq-upload-cancel'>Cancel</button>
<button type='button' class='qq-btn qq-upload-retry-selector qq-upload-retry'>Retry</button>
<button type='button' class='qq-btn qq-upload-delete-selector qq-upload-delete file-section-button btn-primary' onclick='captionUpdate(false);' title='Delete File'><i class='icon-trash icon-white'></i></button>
</div>
<span role='status' class='qq-upload-status-text-selector qq-upload-status-text'></span>
<div class="fileclear"></div>
</div>
</li>
</ul>
<dialog class='qq-alert-dialog-selector'>
<div class='qq-dialog-message-selector'></div>
<div class='qq-dialog-buttons'>
<button type='button' class='qq-cancel-button-selector'>Close</button>
</div>
</dialog>
<dialog class='qq-confirm-dialog-selector'>
<div class='qq-dialog-message-selector'></div>
<div class='qq-dialog-buttons'>
<button type='button' class='qq-cancel-button-selector'>No</button>
<button type='button' class='qq-ok-button-selector'>Yes</button>
</div>
</dialog>
<dialog class='qq-prompt-dialog-selector'>
<div class='qq-dialog-message-selector'></div>
<input type='text'>
<div class='qq-dialog-buttons'>
<button type='button' class='qq-cancel-button-selector'>Cancel</button>
<button type='button' class='qq-ok-button-selector'>Ok</button>
</div>
</dialog>
</div>
Caption Update Button Click:
uploaderContainer.addEventListener('click', function(event) {
isCaptionUpdateClick = false;
if (event.target.className.indexOf('icon-pencil') >= 0) {
isCaptionUpdateClick = true;
};
});
My Delete Parameter setup:
deleteFile: {
enabled: true,
method: "POST",
endpoint: "/ci/fine/endpoint",
params: {
qqcaptionupdate: function() {
if (isCaptionUpdateClick === true) {
return 'YES';
}
},
qqcaption: function() {
return captionValue;
},
bookid: function() {
return $("#book_id").val();
},
sectionid: function() {
return $('#'+uploaderInfo.sectionIdSelector+'').val();
},
}
}

kendo ui mobile events in templates not fireing

I using this approach for my new app.
http://blogs.telerik.com/blogs/14-03-27/structuring-hybrid-mobile-applications
But I running in a problem with click events when I calling templates in my view.
Everything else like data binding init kendo widgets works fine.
What I missing here?
<div data-role="view" id="home" data-model="APP.home.model" data-init="APP.home.events.init" data-after-show="APP.home.events.afterShow" style="display: none;">
<header data-role="header">
<div data-role="navbar">
<a data-role="button" data-rel="drawer" href="#categories" data-icon="drawer-button" data-align="left"></a>
<span data-role="view-title"></span>
<div data-role="button" data-bind="click: hello" data-align="right" data-icon="compose">a</div>
</div>
</header>
<div>TEST me</div>
<div data-role="button" data-bind="click: hello" data-align="right" data-icon="compose">a</div>
<div id="testMe">
</div>
<div id="home-grid" class="grid home-grid"></div>
</div>
<script>
var events = {
init: function (e) {
navbar = e.view.header.find('.km-navbar').data('kendoMobileNavBar');
var template = kendo.template($("#testMe_tmp").html());
$("#testMe").html(template({}));
kendo.mobile.init($("#testMe"));
},
afterShow: function (e) {
navbar.title("b");
}
};
</script>
Thanks in advance
T.S
I found a solution
after
kendo.mobile.init($("#testMe"));
add this
kendo.bind($("#content"),model);
I don't understand why then I never find a sample source need this.
T.S

Resources