Data-binding works first time only, in a detail view - kendo-mobile

In this plunker sample, data-binding of the detail view works on first show, but does not update when navigating to other items.
What is missing ? Thanks!
Html:
<body>
<div data-role="view" data-model="aViewModel" id="aView">
<div data-role="header">
<div data-role="navbar">
<span data-role="view-title">Master</span>
</div>
</div>
<ul data-role="listview" data-style="inset"
data-bind="source: items, events : { click : onClickItem}"
data-template="itemsTemplate">
<script id="itemsTemplate" type="text/html" >
#:name#
</script>
</ul>
</div>
<div data-role="view" id="aDetailView"
data-model="aViewModel.currentItem"
data-show="aViewModel.onDetailViewShow">
<div data-role="header">
<div data-role="navbar">
<span data-role="view-title" data-bind="text:name"></span>
<a data-align="left" data-role="backbutton">Back</a>
</div>
</div>
<ul data-role="listview" data-style="inset" >
<li>Name <span data-bind="text: name"></span></li>
<li>Value <span data-bind="text: value"></span></li>
</ul>
</div>
<script src="script.js"></script>
JS:
var app = new kendo.mobile.Application(document.body );
ViewModel = function () {
var self = this;
function Item (name, value)
{
this.name = name;
this.value = value;
}
self.items = new kendo.data.DataSource({
data: [
new Item("AAA",1),
new Item("BBB",2),
new Item("CCC",3)
]
});
self.currentItem = null;
self.onClickItem = function(e) {
e.preventDefault();
self.set("currentItem", e.dataItem);
app.navigate("#aDetailView", "slide");
}
self.onDetailViewShow = function(e) {
}
self = kendo.observable(this);
return self;
};
var aViewModel = new ViewModel();

Related

Laravel Ajax Add To Cart Not working 500 internal error

I have code I am working on. I will list the page, the route, and the controller code. When I inspect and click on the add to cart button I get 500 internal server error and I cannot figure out what I did. It should be giving a message checking to see if the item is already in the cart and if not send a message saying item is in the cart but I can't get past the 500 internal server error.
Page
#extends('layouts.frontend.frontend')
#section('title')
Distinctly Mine - {{$products->name}}
#endsection
#section('content')
<div class="py-3 mb-4 shadow-sm babyblue border-top">
<div class="container">
<h6 class="mb-0">Collections / {{$products->category->name}} / {{$products->name}}</h6>
</div>
</div>
<div class="container">
<div class="card-shadow shadow-sm product_data">
<div class="card-body">
<div class="row">
<div class="col-md-4 border-right">
<div class="img-hover-zoom img-hover-zoom--xyz card-img-top">
<img src="{{ asset('backend/uploads/products/'.$products->image) }}" class="w-100 h-100" alt="{{$products->name}}">
</div>
</div>
<div class="col-md-8">
<h2 class="mb-0">{{ $products->name}}</h2>
<hr>
<label for="" class="me-3">Price: ${{$products->original_price}}</label>
<p class="mt-3">{!! $products->small_description !!}</p>
<hr>
#if($products->qty > 0)
<label for="" class="badge bg-success text-dark fw-bold">In Stock</label>
#else
<label for="" class="badge bg-danger text dark fw-bold">Out of Stock</label>
#endif
<div class="row mt-2">
<div class="col-md-2">
<input type="hidden" value="{{$products->id}}" class="prod_id">
<label for="Quantity">Quantity</label>
<div class="input-group text-center mb-3" style="width:130px">
<button type="button" class="input-group-text decrement-btn">-</button>
<input type="text" name="quantity" value="1" class="form-control qty-input" />
<button type="button" class="input-group-text increment-btn">+</button>
</div>
</div>
<div class="col-md-10">
<br />
<button type="button" class="btn btn-warning text-dark fw-bold ms-3 float-start"><i class=" me-1 fa fa-heart text-danger me-1"></i>Add To Wishlist</button>
<button type="button" class="btn btn-success ms-3 float-start text-dark fw-bold addToCartBtn"><i class="me-1 fa fa-shopping-cart text-dark me-1"></i>Add to Cart</button>
</div>
<hr>
<h2>Description</h2>
{{$products->description}}
</div>
</div>
</div>
</div>
</div>
</div>
#endsection
#section('scripts')
<script>
$(document).ready(function (){
$('.addToCartBtn').click(function (e){
e.preventDefault();
var product_id = $(this).closest('.product_data').find('.prod_id').val();
var product_qty = $(this).closest('.product_data').find('.qty-input').val();
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
method: "POST",
url: "/add-to-cart",
data: {
'product_id': product_id,
'product_qty': product_qty,
},
dataType: "dataType",
success: function (response){
alert(response.status);
}
});
});
$('.increment-btn').click(function (e){
e.preventDefault();
var inc_value = $('.qty-input').val();
var value = parseInt(inc_value,10);
value = isNaN(value) ? 0 :value;
if(value < 10)
{
value++;
$('.qty-input').val(value);
}
});
$('.decrement-btn').click(function (e){
e.preventDefault();
var dec_value = $('.qty-input').val();
var value = parseInt(dec_value,10);
value = isNaN(value) ? 0 :value;
if(value > 1)
{
value--;
$('.qty-input').val(value);
}
});
});
</script>
#endsection
Route
Route::middleware(['auth'])->group(function (){
Route::post('/add-to-cart',[CartController::class,'addProduct']);
});
Controller
<?php
namespace App\Http\Controllers\Frontend;
use App\Models\Product;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
class CartController extends Controller
{
public function addProduct(Request $request)
{
$product_id = $request->input('product_id');
$product_qty = $request->input('product_qty');
if(Auth::check())
{
$prod_check = Product::where('id',$product_id)->first();
if($prod_check)
{
if(Cart::where('prod_id',$product_id)->where('user_id',Auth::id())->exists())
{
return response()->json(['status' => $prod_check->name." Already Added to cart"]);
}else{
$cartItem = new Cart();
$cartItem->prod_id = $product_id;
$cartItem->user_id = Auth::id();
$cartItem->prod_qty = $product_qty;
$cartItem->save();
return response()->json(['status'=>$prod_check->name." Added to cart"]);
}
}
}
else{
return response()->json(['status'=> "Login To Continue"]);
}
}
}

Kendo Dropdown sync not working inside Kendo Menu

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>

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.

Dynamically bind data with button in Knockout.js?

I'm using MVC3 with Knockout.js and want to attach some data from the api to my button with data-bind=addContribute in a template. This button should open a pop up box and I need the attached button data on that pop up. How can I do this?
My template:
<div>
<ul data-bind="template: {name: 'membersTemplate', foreach: viewModel.membersList}">
</ul>
</div>
<script id="membersTemplate" type="text/html">
<li>
<div class="fl width165">
<img src=" ${ image } " width="33" height="34" />
<span> ${ memberName } </span>
${ memberType }
</div>
<aside class="fr margint10">
<label> ${ contributions } </label>
<a href="#" class="sprite-add_img" id="openContribute" title="Add Contributes to Goals" data-bind="click: viewModel.addContribute" ></a>
</aside>
</li>
</script>
<script id="membersTemplate" type="text/html">
<li>
<div class="fl width165">
<img data-bind="attr : {src : img}" width="33" height="34" />
<span data-bind="text : memberName"></span>
<span data-bind="text : memberType"></span>
</div>
<aside class="fr margint10">
<label data-bind="text : contributions"></label>
<a href="#" class="sprite-add_img" id="openContribute" title="Add Contributes to Goals" data-bind="click: addContribute" ></a>
</aside>
</li>
</script>
membersList varibale in you code should be next
function SingleMember(img, name, type, contr)
{
var self = this
self.img = ko.observable(img)
self.memberName = ko.observable(name)
self.memberType = ko.observable(type)
self.contributions = ko.observable(contr)
self.addContribute = function() {
//
}
}
window.viewModel = new function()
{
var self = this
self.membersList = ko.observableArray()
self.membersList.push(new SingleMember(/*.... params1*/))
self.membersList.push(new SingleMember(/*.... params2*/))
}

layout difficulty in MVC3

I am having a login page. In the login Page I don`t have any menu and based upon the user login a menu appear on the Home page.
My problem is how not to display the menu only in my login page?
I am having a page MenuControlPartial.cshtml as follows for the menu:
<li>Admin
<ul>
<li>TimeKeeper</li>
<li>AAA</li>
<li>BBB</li>
<li>CCC</li>
</ul>
</li>
<li>Settings
<ul>
<li>VV</li>
<li>XX</li>
</ul>
</li>
</ul>
My _layout.cshtml is as as follows:
<div id="page">
<div id="header">
<div id="title">
<br />
</div>
#if (Request.IsAuthenticated)
{
<div id="loginInfo">
#Html.Partial("_LogOnPartial")
</div>
<div class="clear">
</div>
<div id="menucontainer">
#Html.Partial("MenuControlPartial")
</div>
<div class="clear"></div>
}
</div>
<div id="content">
#RenderBody()
</div>
</div>
}
</body>
You could test the current controller and action
#if (!(Html.ViewContext.RouteData.GetRequiredString("controller") == "Login" && Html.ViewContext.RouteData.GetRequiredString("action") == "Index")) {
<div id="menucontainer">
#Html.Partial("MenuControlPartial")
</div>
}
And to avoid this ugliness write a helper:
public static bool ShouldDisplayMenu(this HtmlHelper htmlHelper)
{
var routeData = htmlHelper.ViewContext.RouteData;
var controller = routeData.GetRequiredString("controller");
var action = routeData.GetRequiredString("action");
return !(controller == "Login" && action == "Index");
}
and then:
#if (Html.ShouldDisplayMenu()) {
<div id="menucontainer">
#Html.Partial("MenuControlPartial")
</div>
}

Resources