kendo sortable widget mvvm UI glitch - mvvm

I am using kendo's mvvm and sortable widget to allow a user to sort multiple tables with data binded to it. I have implemented the following code. It works, but the data seems to be logging correctly to the console. However, the data in the UI jumps around.
$(".sortable-handlers").kendoSortable({
handler: ".move",
hint:function(element) {
return element.clone().addClass("sortable-hint");
},
change: function(e) {
var services = viewModel.get("services");
console.log(e.oldIndex);
var oldIndex = e.oldIndex;
var newIndex = e.newIndex;
services.splice(newIndex, 0, services.splice(oldIndex, 1)[0]);
//Set it back to the original list
viewModel.set("services", services);
console.log(JSON.stringify(viewModel.get("services")));
}
});

It's been a long time but adding .trigger("change") works for me (I'm using jquery ui sortable instead of kendo ui sortable).
// Define model with dependent method
var MyModel = kendo.data.Model.define({
fields: {
left: "number",
right: "number"
},
total: function() {
return this.get("left") + this.get("right");
}
});
// Create view model
var viewModel = kendo.observable({
items: []
});
// bindings
kendo.bind($("#myView"), viewModel);
// using $.ui.sortable when list changes
var timeout = null;
viewModel.items.bind("change", function(e) {
clearTimeout(timeout);
timeout = setTimeout(function() {
$("#sortable").sortable({
update: function(e, ui) {
// get UID of sorting target
var targetUid = ui.item.attr("uid");
// list before
var beforeIndexes = _.map(viewModel.items, _.iteratee("uid"));
// target's original index
var fromIdx = _.indexOf(beforeIndexes, targetUid);
// list after
var afterIndexes = $("#sortable").sortable("toArray", {
attribute: "uid"
});
// target's new index
var toIdx = _.indexOf(afterIndexes, targetUid);
var changeItem = viewModel.items[fromIdx];
viewModel.items.splice(fromIdx, 1);
if (toIdx >= viewModel.items.length) {
viewModel.items.push(changeItem);
} else {
viewModel.items.splice(toIdx, 0, changeItem);
}
// refresh
viewModel.items.trigger("change");
}
});
}, 500);
});
// add some items to list
viewModel.items.push(new MyModel({
left: 1,
right: 2
}));
viewModel.items.push(new MyModel({
left: 6,
right: 3
}));
viewModel.items.push(new MyModel({
left: 5,
right: 7
}));
<link href="https://code.jquery.com/ui/1.12.0-beta.1/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<link href="https://kendo.cdn.telerik.com/2016.1.112/styles/kendo.common.min.css" rel="stylesheet" />
<link href="https://kendo.cdn.telerik.com/2016.1.112/styles/kendo.default.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.0-beta.1/jquery-ui.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2016.1.112/js/kendo.all.min.js"></script>
<script src="http://underscorejs.org/underscore-min.js"></script>
<div id="myView">
<div class="k-grid k-widget">
<div class="k-grid-header">
<div class="k-grid-header-wrap">
<table>
<thead>
<tr>
<th class="k-header">SORTABLE</th>
</tr>
</thead>
</table>
</div>
</div>
<div class="k-grid-content">
<table>
<tbody id="sortable" data-bind="source: items" data-template="template-item">
</tbody>
</table>
</div>
</div>
<div class="k-grid k-widget">
<div class="k-grid-header">
<div class="k-grid-header-wrap">
<table>
<thead>
<tr>
<th class="k-header">NOT-SORTABLE</th>
</tr>
</thead>
</table>
</div>
</div>
<div class="k-grid-content">
<table>
<tbody id="sortable" data-bind="source: items" data-template="template-item">
</tbody>
</table>
</div>
</div>
</div>
<script type="text/x-kendo-template" id="template-item">
<tr data-bind="attr: {uid: uid}">
<td>
<span data-bind="text: left" />+
<span data-bind="text: right" />=
<span data-bind="text: total" />
</td>
</tr>
</script>

Related

How can I use v-for tag to show elements in the data?

I am creating ec mock-up, and how can I use v-for tag
developing environment
Mac, Vue.js, Atom, Server hostname is https://euas.person.ee/
Rigth Now↓
What I want to do is showing Order ID and Option Image for each row like
Order ID | OrderDescription | Action
1 "OptionImage" Detail Button
OrderListingVue
<template>
<div class="OrderListing">
<h2>My Orders</h2>
<table class="table">
<tr>
<th>OrderId</th>
<th>OrderDescription</th>
<th>Action</th>
</tr>
<tr v-for="(cart, order) in this.orders" :key="order.id">
<td>{{order}}</td>
<td>{{cart}}</td>
<td>
<b-button variant="dark" :to=" '/orders/' + order">Detail</b-button>
</td>
</tr>
</table>
</div>
</template>
<script>
import axios from "axios";
export default {
name: 'OrderListing',
props: {
order: Object
},
data: function() {
return {
orders: []
}
},
mounted() {
axios.get("https://euas.person.ee/user/orders")
.then(response => {
this.orders = response.data;
});
}
}
</script>
<style scoped>
.option-image {
max-height: 50px;
max-width: 100px;
}
</style>
Addition
ShoppingCartVue↓
<template>
<div class="shopping-cart-page">
<h2>ShoppingCart</h2>
<table class="table">
<tr>
<th>Product</th>
<th>Price</th>
<th>qty</th>
<th>Amount</th>
<th>Actions</th>
</tr>
<tr v-for="(item, index) in this.items" :key="item.productId + '_' + index">
<td>
<img :src="item.optionImage" class="option-image" />
</td>
<td>{{ item.price }}</td>
<td>{{ item.qty }}</td>
<td>{{ item.total }}</td>
<td>
<b-button variant="danger" #click="removeItem(index)">Remove</b-button>
</td>
</tr>
<tr class="total-row">
<td>TOTAL:</td>
<td></td>
<td></td>
<td>{{ total }}</td>
<td></td>
</tr>
</table>
<b-button variant="success" size="lg" #click="orderNow" v-if="this.items.length">Order Now!</b-button>
</div>
</template>
<script>
import axios from "axios";
export default {
name: 'ShoppingCartPage',
computed: {
items: function() {
return this.$root.$data.cart.items || [];
},
total: function() {
let sum = 0
for (const item of this.items) {
sum += item.total
}
return sum
}
},
methods: {
removeItem: function(index) {
if (!this.$root.$data.cart.items) this.$root.$data.cart.items = []
this.$root.$data.cart.items.splice(index, 1);
console.log(this.$root.$data.cart.items);
this.$root.$data.saveCart();
},
orderNow: function() {
let data = this.$root.$data
axios.post("https://euas.person.ee/user/carts/" + this.$root.$data.cart.id + "/orders/",
this.$root.$data.cart).then(function() {
data.reinitCart();
})
}
}
}
</script>
<style scoped>
.option-image {
max-height: 50px;
max-width: 100px;
}
</style>
From what I understood you are looking for something like this:
<div v-for="order in orders" :key="order.id">
<div v-for="item in order.items" :key="item.productId">
<img :src="item.optionImage" class="option-image" />
</div>
</div>

HTML5 Geolocation and Audio in Eclipse internal web browser

I am trying to show audio and google map in a simple HTML5 page. When I run it in other outside browsers like Chrome, Mozilla everything works perfectly.
But same is not working in my eclipse internal web browser and I want the output in that only.
Here is my project link on GitHub:
https://github.com/Venkatesh-Devale/cmpe273/tree/master/StaticRefresher
Please help me know why this is so?
#CHARSET "UTF-8";
#divVideo, #divAudio {
width:40%;
}
#divMyHeader {
background-color:orange;
}
#map {
height: 400px;
overflow: auto !important;
}
html, body {
height: 100%;
margin: 0;
padding: 0;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="UTF-8">
<title>About Me</title>
<link rel="stylesheet" href="hello.css">
</head>
<body>
<div id="divMainPage">
<div id="divMyHeader">
<h1>Venkatesh Devale</h1>
<h6>SJSU ID: 012420148</h6>
</div>
<div id="content">
<p>
I am creating this page to introduce me as we all are pretty new,
through this refresher assignment.
Below is my short video which will tell you about myself.
</p>
<div id="divVideo">
<video controls>
<source src="mov_bbb.mp4" type="video/mp4">
<source src="mov_bbb.ogg" type="video/ogg">
</video>
</div>
<p>
Below is my favorite songs audio. Please guess it.
</p>
<div id="divAudio">
<audio controls>
<source src="horse.ogg" type="audio/ogg">
<source src="horse.mp3" type="audio/mpeg">
</audio>
</div>
</div>
<div id="divFeedbackShowingInputTypes" style="border-style:groove;">
<form>
<table>
<tr>
<td>First Name:</td>
<td><input type="text" name="txtFirstName" autofocus></td>
</tr>
<tr>
<td>Last Name:</td>
<td><input type="text" name="txtLastName"></td>
</tr>
<tr>
<td>Email:</td>
<td><input type="email" name="email" title="<any characters>#<your mail account>.com" pattern="[a-zA-Z]+[#][a-zA-Z]+[.com]" required></td>
</tr>
<tr>
<td>Telephone:</td>
<td><input type="tel" name="phone" title="XXX-XXX-XXXX" pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}" required></td>
</tr>
<tr><td></td>
<td><input type="submit" name="btnSubmit" value="Submit"></td>
</tr>
</table>
</form>
</div>
<div id="myGeoLocatioWithMap">
<div id="map">
</div>
</div>
</div>
<script>
var myMap, myLocationPanel;
function getFirstMap() {
myMap = new google.maps.Map(document.getElementById('map'), {
center: {lat: -58.397, lng: 197.644},
zoom: 7
});
myLocationPanel = new google.maps.InfoWindow;
if (navigator.geolocation) {
console.log("Geolocation is available");
navigator.geolocation.getCurrentPosition(showMyPosition, findLocationNotFoundError);
} else {
handleLocationError(false, myLocationPanel, myMap.getCenter());
}
}
function showMyPosition(position) {
console.log("Geolocation is available");
var myPosition = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
myLocationPanel.setPosition(myPosition);
myLocationPanel.setContent("Your location is here");
myLocationPanel.open(myMap);
myMap.setCenter(myPosition);
var marker = new google.maps.Marker({
position: myPosition,
map: myMap
});
}
function findLocationNotFoundError() {
showLocationError(true, myLocationPanel, myMap.getCenter());
}
function showLocationError(checkDoesBrowserHasLocation, myLocationPanel, mapCenter) {
myLocationPanel.setPosition(mapCenter);
if(checkDoesBrowserHasLocation) {
myLocationPanel.setContent('Somehow geolocation service is not working, we are fixing it');
} else {
myLocationPanel.setContent('Seems that the browser does not support the geolocation');
}
myLocationPanel.open(myMap);
}
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBd-SiW0EEjuidG6nhM6iSeDt9epJPvYno&callback=getFirstMap">
</script>
</body>
</html>

ngTable can't generate header

I'm using ngTable with this code:
HTML:
<table data-ng-table="tableParams" class="table table-condensed table-bordered table-striped">
<tbody>
<tr data-ng-repeat="task in $data">
<td data-title="''">
<input type="checkbox" style="display: block; margin: auto;" ng-model="task.IsSelected" ng-change="optionToggled()">
</td>
<td data-title="''" style="text-align: center">
<i class="glyphicon glyphicon-flag" ng-show="task.IsToday"></i>
<i class="glyphicon glyphicon-ok" ng-show="task.IsCompleted"></i>
</td>
<td data-title="'Subject'" data-sortable="'Subject'">{{task.Subject}}</td>
<td data-title="'Priority'" data-sortable="'PriorityValue'">{{task.PriorityValue}}</td>
<td data-title="'Status'" data-sortable="'StatusValue'">{{task.StatusValue}}</td>
<td data-title="'Due Date'" data-sortable="'DueDate'">{{task.DueDate}}</td>
<td data-title="'Completed'" data-sortable="'CompletedValue'">{{task.CompletedValue}}</td>
<td data-title="'Date Completed'" data-sortable="'DateCompleted'">{{task.DateCompleted}}</td>
<td data-title="'Action'">
<button type="button" style="display: block; margin: auto;" class="btn btn-info btn-xs" ng-click="editRow(task)">
<i class="glyphicon glyphicon-edit"></i>
</button>
</td>
</tr>
</tbody>
</table>
Javascript:
$scope.tableData = [];
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 10, // count per page
sorting: { DueDate: "asc" } // initial sort order,
},
{
paginationMaxBlocks: 10,
paginationMinBlocks: 2,
getData: function($defer, params) {
var sorting = params.sorting();
var keySorting = Object.keys(sorting)[0];
var valueSorting = sorting[keySorting];
var count = params.count();
var pageIndex = params.page() - 1;
var keySearch = angular.isDefined($scope.textSearch) ? $scope.textSearch : '';
taskService.pagingTasks(pageIndex * count, count, keySearch, keySorting, valueSorting).then(function(data) {
var obj = angular.fromJson(data);
params.total(obj.Total);
formatToDateTime(obj.Data);
$scope.tableData = obj.Data;
$defer.resolve(obj.Data);
});
}
});
But when I run my website I see ngTable generate
And my browser console show this error:
I have no idea why ngTable can't generate columns header.
Currently, I must create columns header by manually.
I found my answer:
You can fix this issues base on this post :
AngularJS: 'Template for directive must have exactly one root element' when using 'th' tag in directive template
Modified these lines in file "ng-table.js" and remove tr tag in : "filterRow.html", "groupRow.html", "sorterRow.html".
(template)
$templateCache.put('ng-table/header.html', '<tr ng-if="params.hasGroup()" ng-show="$groupRow.show" class="ng-table-group-header" ng-table-group-row></tr> <tr class="ng-table-sort-header headerrow" ng-table-sorter-row></tr> <tr ng-show="show_filter" class="ng-table-filters" ng-table-filter-row></tr> ');
(directive)
function ngTableGroupRow(){
var directive = {
restrict: 'A',
//replace: true,
templateUrl: 'ng-table/groupRow.html',
scope: true,
controller: 'ngTableGroupRowController',
controllerAs: 'dctrl'
};
return directive;
}
function ngTableSorterRow(){
var directive = {
restrict: 'A',
//replace: true,
templateUrl: 'ng-table/sorterRow.html',
scope: true,
controller: 'ngTableSorterRowController'
};
return directive;
}
function ngTableFilterRow(){
var directive = {
restrict: 'A',
//replace: true,
templateUrl: 'ng-table/filterRow.html',
scope: true,
controller: 'ngTableFilterRowController'
};
return directive;
}

Update partialview after Model updaton using Model popup

I have index page which contains 2 partial views.One for displaying Roles and another for displaying corresponding privileges.
#model IEnumerable<sample.Models.Role_Privilege_Map>
#{
ViewBag.Title = "RolePrivilgeMapping";
}
<h2>RolePrivilgeMapping</h2>
<script>
$(document).ready(function () {
registerTableClick();
//$("#tblRole tbody tr:first").trigger();
});
function registerTableClick() {
$("#tblRole tbody tr").on("click", function () {
$(this).siblings().removeClass('selected_row');
$(this).addClass("selected_row");
var roleId = parseInt($(this).find("td:eq(0)").text());
loadPrivilege(roleId);
});
function loadtrackPrivilege(roleId) {
$("#PrivilegeWrapper").load("#Url.Action("PrivilegesPartial", "RolePrivilegeMapping")",
{ 'roleID': roleId },
function (response, status, xhr) {
if (status == "error") {
alert("An error occurred while loading privileges.");
}
});
}
}
</script>
<div id="RolePrivilgeMappingWrapper">
<div class="float-left" id="roleWrapper">
#Html.Partial("_Role", sample.Models.DataProvider.DataProvider.GetRoleNames())
</div>
<div class="float-left" id="PrivilegeWrapper">
#Html.Partial("_Privilege", sample.Models.DataProvider.Provider.GetPrivilegeNames())
</div>
</div>
Here is my _Role.cshtml
#model IEnumerable<sample.Models.webpages_Roles>
#{
ViewBag.Title = "Index";
}
<script type="text/ecmascript">
$(document).ready(function () {
$.ajaxSetup({ cache: false });
$(".editDialog").live("click", function (e) {
var url = $(this).attr('href');
$("#dialog-edit").dialog({
title: 'Edit Role',
autoOpen: false,
resizable: false,
height: 255,
width: 400,
show: { effect: 'drop', direction: "up" },
modal: true,
draggable: true,
open: function (event, ui) {
$(this).load(url);
},
close: function (event, ui) {
$(this).dialog('close');
}
});
$("#dialog-edit").dialog('open');
return false;
});
});
</script>
<div class="settingsTable" style="position: relative; width: 100%; margin: 0 auto">
<div style="width: 50%; margin: 0 auto">
<div style="width: 50%; margin: 0 auto">
<h2>Role</h2>
</div>
</div>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table id="tblRole">
<tr>
<th>
#Html.DisplayNameFor(model => model.RoleId)
</th>
<th>
#Html.DisplayNameFor(model => model.RoleName)
</th>
<th>Action</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.RoleId)
</td>
<td>
#Html.DisplayFor(modelItem => item.RoleName)
</td>
<td>
#Html.ActionLink("Edit", "OpenEditRoleDialog", "RolePrivilegeMapping", new { id = item.RoleId }, new { #class="editDialog"}) |
#Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</table>
<div id="dialog-edit" style="display: none">
</div>
</div>
On Role partial view I have edit link for every row displayed.
here is my _editrole.cshtml
#model sample.Models.webpages_Roles
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Ajax.BeginForm("EditRole", "RolePrivilegeMapping", new AjaxOptions { HttpMethod = "POST" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>webpages_Roles</legend>
#Html.HiddenFor(model => model.RoleId)
<div class="editor-label">
#Html.LabelFor(model => model.RoleName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.RoleName)
#Html.ValidationMessageFor(model => model.RoleName)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
Now while I click on edit link a jquery modal box gets displayed for editing details.I submit the changes asychronously as
#using (Ajax.BeginForm("EditRole", "RolePrivilegeMapping", new AjaxOptions { HttpMethod = "POST" }))
And the edit method is
public ActionResult EditRole(webpages_Roles webpages_roles)
{
if (ModelState.IsValid)
{
db.Entry(webpages_roles).State = EntityState.Modified;
db.SaveChanges();
}
return View("index");
}
My problem is
1. The dialog box is not getting closed. I have to manually click the cross
bar.
2. The Role partial view is not getting updated until I have to refresh the page.
I followed this link http://www.mindstick.com/Articles/279bc324-5be3-4156-a9e9-dd91c971d462/CRUD%20operation%20using%20Modal%20dialog%20in%20ASP%20NET%20MVC#.VVlyBLmqpHx

jQuery Datepicker only firing if I first click on another input field

I'm having some strange behaviour when using the datepicker. When I load the page, and directly click on the datepicker input, nothing happens. When I click again, nothing happens. But when I click on another input field and then try again the datepicker field, it'll show up.
The issue showed up, after I put the datepicker trigger into a live function, because I have input which will be dynamically generated.
This is my code:
$(".date").on('click', function() {
$(this).datepicker({
dateFormat: "dd.mm.yy",
altField: $(this).closest("td").find(".dateFormated"),
altFormat: "yy-mm-dd"
})
})
Edit: I have seen that live() is deprecated as of 1.7. I therefore switched live() for on(). Didn't solve the issue though.
Whole Html
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html" />
<meta name="author" content="gencyolcu" />
<title>Untitled 1</title>
<link rel="stylesheet" href="http://localhost:8082/ivy/page/designer/ZWM$1/css/cupertino/jquery-ui-1.9.2.custom.css" />
<script type="text/javascript" src="http://localhost:8082/ivy/page/designer/ZWM$1/jquery.min.js"></script>
<script type="text/javascript" src="http://localhost:8082/ivy/page/designer/ZWM$1/js/jquery-ui-1.9.2.custom.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
counter = 0;
$("#addRow").click(function() {
counter++;
rowHtml = '\
<tr class="datarow" id="row' + counter + '">\
<td><input type="text" class="date" /><input type="text" class="dateFormated" /></td>\
<td><input type="text" class="from" /></td>\
<td><input type="text" class="to" /></td>\
<td>\
<select class="type">\
<option value="1">Typ 1</option>\
<option value="2">Typ 2</option>\
</select>\
</td>\
<td class="removeRow" id=' + counter + '>X</td>\
</tr>';
$('#submitButton').before(rowHtml);
})
$(".removeRow").live("click", function() {
id = $(this).attr("id");
$("#row" + id).remove();
})
$("[name=formZeitdaten]").submit(function(i) {
values = "";
$(".datarow").each(function(j) {
tr = $(this);
date = tr.find('td').find('.date').val();
from = tr.find('td').find('.from').val();
to = tr.find('td').find('.to').val();
type = tr.find('td').find('.type').val();
values = values + date + ',' + from + ',' + to + ',' + type + ';';
})
console.log(values);
$("[name=dataset]").val(values);
})
$("#slider").slider({
range: true,
min: 0,
max: 1440,
step: 15,
values: [30, 210],
slide: function(event, ui) {
$(".date").val(ui.values[0] + ":" + ui.values[1]);
}
});
$(".date").on('click', function() {
$(this).datepicker({
dateFormat: "dd.mm.yy",
altField: $(this).closest("td").find(".dateFormated"),
altFormat: "yy-mm-dd"
})
})
});
</script>
</head>
<body>
<span id="test"></span>
<form name="formZeitdaten" method="post">
<table id="zeitdaten">
<tr>
<td>Datum</td>
<td>Von</td>
<td>Bis</td>
<td>Typ</td>
<td id="addRow"><input type="button" value="Hinzufügen" /></td>
</tr>
<tr class="datarow">
<td><input type="text" class="date" /><input type="text" class="dateFormated" /></td>
<td><input type="text" class="from" /></td>
<td><input type="text" class="to" /></td>
<td>
<select class="type">
<option value="1">Typ 1</option>
<option value="2">Typ 2</option>
</select>
</td>
<td></td>
</tr>
<tr id="submitButton">
<td><input type="submit" /></td>
</tr>
</table>
</form>
<div id="slider"></div>
</body>
</html>
In your addRow function, add:
$("#row"+counter+" .date").datepicker({
dateFormat: 'dd-mm-yy',
minDate: 0,
showButtonPanel: true,
showAnim: 'show'
});
after you add the element to the DOM. You can then get rid of the $(".date").on('click',...) statement later.
This should work for you
$('.date').datepicker({
dateFormat: 'dd-mm-yy',
minDate: 0,
showButtonPanel: true,
showAnim: 'show'
});