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
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"]);
}
}
}
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>
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.
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*/))
}
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>
}