How to get length of Kendo HierarchicalDataSource with remote data? - javascript

I'm working on a Javascript function that will set a kendo.data.HierarchicalDataSource object using a url that fetches the data. At the end of this function, if the data source actually has data, I want to set a treeview with the data (which is already working). If it doesn't have data, instead of setting the treeview, I want to make a label visible that tells the user that there is no data.
My problem: How to I determine that there is/isn't data in the HierarchicalDataSource? When I try call any function or get any property of getData, it returns undefined.
function loadTreeGroupData(applicationId) {
var treeview = $("#treeview-kendo").data("kendoTreeView");
var url = $('#urlHolders').data("gettreeUrl");
var appId = 0;
if (applicationId != undefined && applicationId != "")
appId = applicationId;
var getData = new kendo.data.HierarchicalDataSource({
change: function (e) {
for (var i = 0; i < e.items.length; i++) {
e.items[i].load();
}
},
transport: {
read: {
url: url, //"GetAlertsTree",
dataType: "json",
contentType: "application/json",
data: { applicationId: appId }
}
},
schema: {
model: {
id: "id",
hasChildren: "hasChildren",
children: "measureGroups"
}
}
});
if (/*the treeview has data*/) {
treeview.setDataSource(getData);
} else {
/*set a label that tells the user that there's no data*/
}
}

I would suggest you to do the following changes in your code:
Set the HierarchycalDataSource at the treeView initialization, instead of add it later;
Declare treeView's div and label as display:none or whatever the way you hide them;
Use DataSource's requestEnd event to show/hide the elements.
<!DOCTYPE html>
<html>
<head>
<base href="https://demos.telerik.com/kendo-ui/treeview/remote-data-binding">
<style>html { font-size: 14px; font-family: Arial, Helvetica, sans-serif; }</style>
<title></title>
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2021.2.616/styles/kendo.default-v2.min.css" />
<script src="https://kendo.cdn.telerik.com/2021.2.616/js/jquery.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2021.2.616/js/kendo.all.min.js"></script>
</head>
<body>
<div id="example">
<div class="demo-section k-content">
<div id="treeview" style="display: none"></div>
<div id="no-data-label" style="display: none">No data found</div>
</div>
<script>
var serviceRoot = "https://demos.telerik.com/kendo-ui/service";
homogeneous = new kendo.data.HierarchicalDataSource({
transport: {
read: {
url: serviceRoot + "/Employees",
dataType: "jsonp"
}
},
schema: {
model: {
id: "EmployeeId",
hasChildren: "HasEmployees"
}
},
requestEnd: (e) => {
if (e.response && e.response.length) {
$("#treeview").show();
$("#no-data-label").hide();
}
else {
$("#treeview").hide();
$("#no-data-label").show();
}
}
});
$("#treeview").kendoTreeView({
dataSource: homogeneous,
dataTextField: "FullName"
});
</script>
</div>
</body>
</html>
Dojo

Related

Knockout JS How to Access a Value from Second View Model / Binding

I am new to Knockout JS and think it is great. The documentation is great but I cannot seem to use it to solve my current problem.
The Summary of my Code
I have two viewmodels represented by two js scripts. They are unified in a parent js file. The save button's event is outside
both foreach binders. I can save all data in the details foreach.
My Problem
I need to be able to include the value from the contacts foreach binder with the values from the details foreach binder.
What I have tried
I have tried accessig the data from both viewmodels from the parent viewmodel and sending the POST request to the controller from there but the observeableArrays show undefined.
Create.CSHTML (Using MVC5 no razor)
<div id="container1" data-bind="foreach: contacts">
<input type="text" data-bind="value: contactname" />
</div>
<div data-bind="foreach: details" class="card-body">
<input type="text" data-bind="value: itemValue" />
</div>
The save is outside of both foreach binders
<div class="card-footer">
<button type="button" data-bind="click: $root.save" class="btn
btn-success">Send Notification</button>
</div>
<script src="~/Scripts/ViewScripts/ParentVM.js" type="text/javascript"></script>
<script src="~/Scripts/ViewScripts/ViewModel1.js" type="text/javascript"></script>
<script src="~/Scripts/ViewScripts/ViewModel2.js" type="text/javascript"></script>
ViewModel1
var ViewModel1 = function (contacts) {
var self = this;
self.contacts = ko.observableArray(ko.utils.arrayMap(contacts, function (contact) {
return {
contactName: contact.contactName
};
}));
}
ViewModel2
var ViewModel2 = function (details) {
var self = this;
self.details = ko.observableArray(ko.utils.arrayMap(details, function (detail) {
return {
itemNumber: detail.itemValue
};
}));
}
self.save = function () {
$.ajax({
url: baseURI,
type: "POST",
data: ko.toJSON(self.details),
dataType: "json",
contentType: "application/json",
success: function (data) {
console.log(data);
window.location.href = "/Home/Create/";
},
error: function (error) {
console.log(error);
window.location.href = "/Homel/Create/";
}
});
};
ParentViewModel
var VM1;
var VM2;
var initialContactInfo = [
{
contactPhone: ""
}
]
var initialForm = [
{
itemValue: ""
]
}
$(document).ready(function () {
if ($.isEmptyObject(VM1)) {
ArnMasterData = new ViewModel1(initialContactInfo);
ko.applyBindings(VM1, document.getElementById("container1"));
}
if ($.isEmptyObject(VM2)) {
VM2 = new ViewModel2(initialForm);
ko.applyBindings(VM2, document.getElementById("container2"));
}
});

How to delete an object in django without rendering an html page to get the confirmation

I have created a Blog website and I want to add the functionality to delete a post object while clicking on the Delete button without rendering a separate HTML page rather using the confirm method in JavaScript.
And I have no idea to complete that.
i think you use a .remove method in model object or field
model.field.remove(model_object)
and use this for javascript confirm method
<button onclick="myFunction()">DELETE</button>
<p id="demo"></p>
<script>
function myFunction() {
var txt;
var r = confirm("Press a button!");
if (r == true) {
txt = "You pressed OK!";
} else {
txt = "You pressed Cancel!";
}
document.getElementById("demo").innerHTML = txt;
}
</script>
use this javascript code inside template where the delete button present
i Think this will help you
If you want to delete an object without reload the webpage, you will need to use ajax.
You can define a delete url for each post same as you generate an absolute url. It is easy to do. Here is my approach using jquery ajax and function based django view.
#models.py
class MyModel(models.Model):
def delete_url(self):
return reverse('delete-model', kwargs={'pk': self.id}
#views
def delete_model(request, pk):
item = get_object_or_404(Model, id=pk)
if item:
ref = item.id
item.delete()
data = {'ref': ref, 'message': 'Object with id %s has been deleted' %ref}
return JsonResponse(data)
#urls.py
path('delete/<pk>/', delete_model, name='delete-model')
$(document).ready(function () {
$(".comfirm-delete").click(function (e) {
e.preventDefault();
var proceed = confirm('Proceed with deletion');
if (proceed == true) {
var endpoint = $(this).attr('data-url')
$.ajax({
method: 'GET',
url: endpoint,
success: function (data) {
$.notify({
// options
title: '<b>Message<b> ',
message: data.message,
}, {
// settings
type: 'success',
delay: 3000,
allow_dismiss: true,
});
$("#item" + data.ref).hide(1000)
},
error: function (error_data) {
console.log(error_data);
$.notify({
title: '<b>Error</b><br>',
message: 'Sorry, something gone wrong'
}, {
type: 'danger',
delay: 3000,
})
}
})
} else {
e.preventDefault();
$.notify({
title: '<b>Action cancelled</b><br>',
message: 'This one is not <span class="text-danger">Deleted</span>'
}, {
type: 'info',
delay: 3000,
})
}
})
})
.comfirm-delete {
color: red;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-notify/0.2.0/css/bootstrap-notify.css" integrity="sha256-ibUTW+jDj+F8d1T1KZ4DOujRmVTFfvMKL9y14QgEaPQ=" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-notify/0.2.0/js/bootstrap-notify.min.js"></script>
<table>
<tbody>
{% for obj in objects %}
<tr id="item{{obj.id}}">
<td>{{obj.info}}</td>
<td data-url="{{obj.delete_url}}" class="comfirm-delete">Delete</td>
</tr>
{% endfor %}
</tbody>
</table>

change data key name came from JSON dynamically AngularJS

I have a multi-select that I made with angular-ui.
I want to add an input that user can change the JSON key names so for example if the API that user add doesn't have "name" instead has "firstName" as the "key name" the app changes that and can work fine.
how can I get this result?
appreciate any help.
my code is here
what I really want is this: I should add this multi-select as a widget to a software named bonita studio and it should have an option that user can choose any API that want to use and should have an input field that the user will choose which one of the API's key identifier to iterate. for example if instead of name the user wants to iterate over the email s/he should be able to do.
I hope this explanation is enough
"use strict";
var app = angular.module("myApp", ['ui.select', 'ngSanitize']);
app.controller("myCtrl", function($scope, $http) {
$scope.headers = "";
var counter = 0;
var chunks = 5;
$scope.datas = [];
$scope.getData = function getData() {
return $http({
method: "GET",
url: "data.json"
})
.then(function onSuccess(response) {
for (let i = 0; i < response.data.length; i++) {
$scope.datas.push(response.data[i]);
}
//counter += chunks;
})
.catch(function onError(response) {
console.log(response.status);
});
}
/*$scope.loadMore = function () {
$http({
method: "GET",
url: "data.json"
})
.then(function loadMoreSuccess(response) {
for (let i = counter; i < (counter + chunks); i++) {
$scope.datas.push(response.data[i]);
}
counter += chunks;
})
.catch(function onError(response) {
console.log(response.status);
});
};*/
$scope.selected = {
value: $scope.datas[0]
};
});
#widgetContainer {
width: 100%;
}
ul li {
list-style: none;
text-align: center;
}
ul {
height: 120px;
overflow-y: auto;
}
#loadMore {
text-align: center;
color: #aaa;
background: #ddd;
cursor: pointer;
}
#category {
text-align: center;
background: #ddd;
}
#listContainer {
width: 20%;
}
span {
cursor: pointer;
}
h4 {
background: #ddd;
color: #aaa;
}
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="script/lib/angular/angular.js"></script>
<script src="https://code.angularjs.org/1.6.10/angular-sanitize.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.20.0/select.min.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.20.0/select.min.css">
<link rel="stylesheet" href="stylesheet/style.css">
</head>
<body ng-controller="myCtrl">
<div class="container">
<input type="text" ng-model="headers">
<ui-select multiple spinner-enabled="true" close-on-select="false" ng-model="selected.value">
<ui-select-no-choice>
couldn't find anything...
</ui-select-no-choice>
<ui-select-match placeholder="Select country...">
<span>{{$item.name}}</span>
</ui-select-match>
<ui-select-choices group-by="'category'" repeat="data in (datas | filter: $select.search) track by $index" refresh="getData($select.search)" refresh-delay="0">
<span>{{data.name}}</span>
</ui-select-choices>
</ui-select>
</div>
<script src="script/script.js"></script>
</body>
</html>
// Supose you have an object with desired change relations:
var relations = { firstName: "name", oldKey: "newKey" };
// Also, you have your dataArray:
var dataArray = [
{ firstName: "foo", oldKey: 1 },
{ firstName: "bar", oldKey: 2 }
];
// Here follows how you can switch keys:
Object.entries(relations).map(([oldKey, newKey]) => {
dataArray.map(data => {
data[newKey] = data[oldKey];
delete data[oldKey];
})
});
// Check out the result:
console.log(dataArray);
Loop over it and create a new key name then delete the old one like :
jsonData.forEach((data)=>{
data.name = data.firstName;
delete data.firstName;
})

Adding autocomplete using images to a search box in a MVC application

I’m wondering if anyone can help me.
I’m attempting to create a search box for my MVC application that autocompletes (makes suggestions on the basis of the user's input) with images instead of text.
The feature will check whether the user’s input is similar to a “Title” property from an Entity Framework database table called “Word” and then return it’s “Imagepath” property, which is a string path to the image.
This path should then be used in the View to return a list of relevant images auto completing the user's query. These images are then clickable and link to their respective pages.
Similar to the below but without the text and solely box images:
https://www.algolia.com/doc/assets/images/guides/search-ui/autocomplete-textarea-8-2565ba67.png
I am struggling with the code here as I am unfamiliar with the Ajax and Javascript that I understand is necessary to achieve this in real time.
My attempt is outlined below:
DATABASE MODEL:
The table is essentially this:
public class Word
{
public int Id { get; set; }
public string Title { get; set; }
public string Imagepath { get; set; }
}
CONTROLLER:
_context is the database.
Controller name is "WordsController".
[HttpPost]
public JsonResult AutoComplete(string Prefix)
{
var words= _context.Words.ToList();
var specifiedWords = (from w in words
where w.Title.StartsWith(Prefix) || w.Title.Contains(Prefix)
select new { w.Imagepath });
return Json(specifiedWords , JsonRequestBehavior.AllowGet);
}
VIEW:
Firstly here is my attempt at the Javascript. I am trying to return a list of "Words" from the "Words" Controller above and append their Imagepath property to an HTML element attempting to create a sort of list. The search box and css is below.
<script src="~/Scripts/jquery-3.2.1.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<link rel= "stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css" >
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<script>
$(document).ready(function () {
$("#Title").autocomplete(
{
source: function (request, response) {
$.ajax({
url: "/Words/AutoComplete",
type: "POST",
dataType: "json",
data: { Prefix: request.term },
success: function (data) {
response($.map(data, function (item) {
return {
label: item.Imagepath,
value: item.Title
};
}));
}
});
},
open: (event) => {
$('.ui-autocomplete .ui-menu-item div').toArray().forEach((element) => {
let imagePath = element.innerHTML;
$(element).html('');
var inner_html = '<div class="list_item_container"><div class="image"><img src="' +
imagePath + '"></div>';
$(element).append(inner_html);
});
}
});
});
</script>
Searchbox:
#Html.EditorFor(model => model.Title, new { htmlAttributes = new { #class = "form-control" } })
CSS:
<style>
.list_item_container {
width: 300px;
height: 60px;
padding: 5px 0;
}
.image {
width: 60px;
height: 60px;
margin-right: 10px;
float: left;
}
Needless to say, my best attempts do not yet work.
The JavaScript has been loosely taken from the tutorial here (which only covers autocompletion with words:
http://www.jamiemaguire.net/index.php/2017/04/08/how-to-implement-an-autocomplete-control-with-asp-net-mvc-and-json/
Any pointers or links to useful resources would be massively appreciated. Thanks!
set open. open trigger after response has been received and content has been rendered.
{
source: function(request, response) {
$.ajax({
url: '#Url.Action("AutoComplete", "Words")',
type: "POST",
dataType: "json",
data: { Prefix: request.term },
success: function (data)
{
response($.map(data, function (item)
{
return {
label: item.Imagepath,
value: item.Title
}
}));
}
});
},
open: (event) => {
$('.ui-autocomplete .ui-menu-item div').toArray().forEach((element) => {
let imagePath = element.innerHTML;
$(element).html('');
var inner_html = '<div class="list_item_container"><div class="image"><img src="' +
imagePath + '"></div>';
$(element).append(inner_html);
});
}
}
in case if autocomplete function is not defined or can't be called the following link will be useful .autocomplete is not a function Error
i guess you forgot to return title as well:
var specifiedWords = (from w in words
where w.Title.StartsWith(Prefix) || w.Title.Contains(Prefix)
select new { w.Imagepath, w.Title });
return Json(specifiedWords, JsonRequestBehavior.AllowGet);

CellFilter is getting called before $http Response in UI-Grid

I am using ui-grid to bind data from Role Table which contains Department Id as PrimaryKey. I am calling Web Api to get all the roles in the table and show in ui-grid.
Department Table
Role Table
My real problem is that I want to convert Department Id to Department Name when it binds to grid using cellFilter and that is why I declare objMapping to map Department Id with Department Name. But every time when I run I see that cellFilter custom function i.e. 'mapDepartmentName' is getting called before objMapping is being set and also I am not able to refer objMapping in 'mapDepartmentName'.
My grid looks like this:-
However when I edit I get the result as below which is absolutely correct:-
My code snippet as below:-
var myApp = angular.module('appHome', ['ui.grid', 'ui.grid.edit']);
myApp.controller("ctrlRole", ['$scope', 'MetadataOrgFactory', function ($scope, MetadataOrgFactory) {
var arrDepts = [];
var objMapping = {};
MetadataOrgFactory.getApiCall('getpublisheddepts', function (dataSuccess) {
$scope.department = dataSuccess;
for (var cntElem = 0; cntElem < dataSuccess.length; cntElem++) {
var objDept = { id: dataSuccess[cntElem].DeptId, DeptId: dataSuccess[cntElem].DeptName }
arrDepts.push(objDept);
objMapping[dataSuccess[cntElem].DeptId] = dataSuccess[cntElem].DeptName;
}
$scope.gridRole.columnDefs[1].editDropdownOptionsArray = arrDepts;
}, function (dataError) {
});
$scope.gridRole = {
data: 'roleData',
columnDefs: [
{
field: 'RoleName', displayName: 'Role Name',
},
{
field: 'DeptId', displayName: 'Department Name',
editableCellTemplate: 'ui-grid/dropdownEditor',
cellFilter: 'mapDepartmentName:this',
editDropdownValueLabel: 'DeptId',
},
{
field: 'RoleDesc', displayName: 'About Role',
},
{
field: 'WorkingHrs', displayName: 'Working Hours',
},
{
field: 'RequestNumber', displayName: 'RequestNumber',
cellEditableCondition: true
}
]
}
MetadataOrgFactory.getApiCall('getallroles', function (dataSuccess) {
$scope.roleData = dataSuccess;
}, function (dataError) {
});
}])
.filter('mapDepartmentName', function () {
return function (input, scope) {
if (!input) {
return '';
} else {
return objMapping[input];
}
};
});
<!DOCTYPE html>
<html>
<head>
<title></title>
<style>
.gridStyle {
border: 5px solid #d4d4d4;
height: 200px;
}
</style>
<meta charset="utf-8" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
<link rel="stylesheet" href="https://cdn.rawgit.com/angular-ui/bower-ui-grid/master/ui-grid.min.css" />
<script src="https://cdn.rawgit.com/angular-ui/bower-ui-grid/master/ui-grid.min.js"></script>
<script src="../Scripts/AngularControllers/RoleController.js"></script>
<script src="../Scripts/AngularServices/ApiCallService.js"></script>
</head>
<body ng-app="appHome">
<div ng-controller="ctrlRole">
<div class="gridStyle" ui-grid="gridRole" ui-grid-edit>
</div>
</div>
</body>
</html>
Call $scope.$apply() in getpublisheddepts at the end of factory callback.
as you didnt show ur factory I believe its doing something asynchronously which is not informing the view to reflect changes.
I stuck in the issue for long time.
I did the following change in the code and I am getting the results as well. Please let me know if this is the correct solution for this:-
MetadataOrgFactory.getApiCall('getpublisheddepts', function (dataSuccess) {
$scope.department = dataSuccess;
for (var cntElem = 0; cntElem < dataSuccess.length; cntElem++) {
var objDept = { id: dataSuccess[cntElem].DeptId, DeptId: dataSuccess[cntElem].DeptName }
arrDepts.push(objDept);
objMapping[dataSuccess[cntElem].DeptId] = dataSuccess[cntElem].DeptName;
}
$scope.deptmapping = objDeptMapping; //new code added here
$scope.gridRole.columnDefs[1].editDropdownOptionsArray = arrDepts;
}, function (dataError) {
});
Filter Class
.filter('mapDepartmentName', function () {
return function (input, scope) {
if (!input) {
return '';
} else {
return scope.grid.appScope.deptmapping[input]; //Change in code
}
};
});

Categories