Kendo MVVM - template not updating - javascript

In the code snippet, I want to update a Kendo Template by changing an item of an array.
The problem is: it updates data-bind="text: foo", but it doesn't update #:foo#.
Why?
var viewModel = kendo.observable({
myArray: [
{foo: 'foo not updated'}
],
update() {
this.set('myArray[0].foo', 'foo updated!')
}
});
kendo.bind($(document.body), viewModel);
<div data-bind="source: myArray" data-template="tmp"></div>
<script id="tmp" type="text/x-kendo-template">
<div data-bind="text: foo"></div>
<div>#:foo#</div>
</script>
<button type="button" data-bind="click: update">Update</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2018.2.620/js/jquery.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2018.2.620/js/kendo.all.min.js"></script>

Related

Knockout JS show hide div based on page URL

I want to split two different section based on page URL. I'm not aware how to do it using knockout.
The below example I have tried so far.
<!-- ko if: attr: { href: https://stackoverflow.com } -->
<p>Div 1</p>
<!-- /ko -->
<!-- ko if: attr: { href: https://getbootstrap.com } -->
<p>Div 2</p>
<!-- /ko -->
Any clarification please drop a comment. Thanks in Advance.
You can use the template system to perform this kind of switch :
ko.applyBindings({
stackoverflowData : {
totalQuestions : 321
},
bootstrapData : {
version : '5.0.2'
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.1/knockout-latest.js"></script>
<div data-bind="template: { name: 'stackoverflow-template', data: stackoverflowData }"></div>
<hr />
<div data-bind="template: { name: 'bootstrapData-template', data: bootstrapData }"></div>
<script type="text/html" id="stackoverflow-template">
stackoverflow specific view <br />
Questions: <span data-bind="text: totalQuestions"></span>
</script>
<script type="text/html" id="bootstrapData-template">
bootstrapData specific view <br />
Version <span data-bind="text: version"></span>
</script>
If you want something dynamic you can create a function that returns the template to use based on the viewmodel.
function getTemplate(url) {
// use reg ex
if (url == 'https://stackoverflow.com')
return 'stackoverflow';
if (url == 'https://getbootstrap.com')
return 'bootstrap';
return null;
}
var websites = [{
url: 'https://stackoverflow.com',
specificData: {
totalQuestions: 321
}
},
{
url: 'https://getbootstrap.com',
specificData: {
version: '5.0.2'
}
}
];
websites.map(function(website) {
website.template = ko.computed(function() {
return getTemplate(this.url);
}, website);
return website;
})
ko.applyBindings({
websites: websites
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.1/knockout-latest.js"></script>
<div data-bind="foreach: websites">
<div data-bind="template: { name: (template()+'-template'), data: specificData }">
<hr />
</div>
</div>
<script type="text/html" id="stackoverflow-template">
stackoverflow specific view <br /> Questions: <span data-bind="text: totalQuestions"></span>
</script>
<script type="text/html" id="bootstrap-template">
bootstrapData specific view <br /> Version <span data-bind="text: version"></span>
</script>
To make this work, you'll need to bring the url into your viewmodel. You could do this with a simple custom url bindinghandler. When initialized, it stores the current url in the bound observable (in this case myUrl) and adds an event listener for storing a changed url (in this case I use hash change to be able to make the example work).
Now, in HTML you can show or hide divs based on this observable value. Have a look at the example below.
ko.bindingHandlers.url = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
valueAccessor()(location.href);
window.addEventListener('hashchange', function(ev) {
valueAccessor()(ev.newURL);
});
}
};
ko.applyBindings({
myUrl: ko.observable(),
showDiv1: function() {
window.location.hash = 'div1'
},
showDiv2: function() {
window.location.hash = 'div2'
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<p>
Current url: <em data-bind="text: myUrl"></em>
</p>
<button data-bind="click: showDiv1">Show Div 1</button>
<button data-bind="click: showDiv2">Show Div 2</button>
<div data-bind="url: myUrl">
<!-- ko if: myUrl() == "https://stacksnippets.net/js#div1" -->
<p>Div 1</p>
<p data-bind="text: myUrl"></p>
<!-- /ko -->
<!-- ko if: myUrl() == "https://stacksnippets.net/js#div2" -->
<p>Div 2</p>
<p data-bind="text: myUrl"></p>
<!-- /ko -->
</div>

angular js related to controller and custom directives

i should get output like that in second div i should get inplace of headers i should get income which is mentioned in the controller object data
I just need different content in two div when I changed the data in controller object it should be reflected in div.
here is my html code
<!DOCTYPE html>
<html ng-app="myApp">
<head>
***emphasized text***
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="angular-gridster.min.css"></link>
<link rel="stylesheet" href="wid.css"></link>
</head>
<body ng-controller="myController" >
<div gridster ng-controller="myCtrl" >
<ul>
<li gridster-item="item" ng-repeat="item in Items">
<div my-widget ></div>
</li>
</ul>
</div>
</body>
</html>
my script goes here which contains the controller as well as directive.
var app=angular.module('myApp',['gridster'])
app.controller('myController',function($scope){
$scope.Items = [
{ sizeX: 2, sizeY: 1, row: 0, col: 0, },
{ sizeX: 2, sizeY: 1, row: 0, col: 0, }
]
});
app.controller('myCtrl',function($scope){
$scope.content=[{
data:54565463,
right:67566,
title:'headers'},
{ data:65476756,
right:123,
title:"Income",
}]
});
app.directive('myWidget',function(){
return{
restrict:"EA",
scope:{
title:'#',
data:'=',
},
templateUrl:'spare.html',
}
});
and my spare html is below -
<span ng-controller="myCtrl">
<div class="panel-body " ng-style = "myStyle">
<h1 class="title" >{{content.title}}</h1>
<i class="fa fa-dollar" ></i>{{content.data}}</div>
<p id="rightcorner" ><i class="fa fa-level-up"></i>{{content.right}}
</p>
</span>
what i need is in 2 div's i should get separate data which is giveenter code heren in controller object
Your directive is using an isolated scope (scope:{ title:'#', data:'='}). That's why it doesn't have access to the content array of the parent scope (which is a good thing in general).
What you wanna do is to pass an item of $scope.content to the my-widget directive.
You could use the $index variable of the ngRepeat scope.
<li gridster-item="item" ng-repeat="item in Items">
<div my-widget data="content[$index]"></div>
</li>
As the my-widget directive has its own scope, you have to change the binding expressions (there is no thing called content in the directive scope).
<div class="panel-body">
<h1 class="title" >{{title}}</h1>
<i class="fa fa-dollar" ></i>{{data.data}}
</div>
<p id="rightcorner"><i class="fa fa-level-up"></i>{{data.right}}
</p>
By the way, title is a bad name for an attribute, as it's an html attribute.
EDIT: Added example code for a solution with a single controller, as asked in comments.
angular.module('app', [])
.controller('myController', myController)
.directive('myWidget', myWidget);
function myController() {
var vm = this;
vm.items = [
{
title: "1",
obj: { data: 123 }
},
{
title: "2",
obj: { data: 234 }
}];
}
function myWidget() {
return {
scope: {
data: '<'
},
template: '<div>Widget: {{data.data}}</div>'
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"></script>
<div ng-app="app" ng-controller="myController as $ctrl" >
<div>
<ul>
<li ng-repeat="item in $ctrl.items">
<div ng-bind="item.title"></div>
<div my-widget data="item.obj"></div>
</li>
</ul>
</div>
</div>

Change template dynamic

I have something like this
<script id="template1" type="text/html">
<h3>Template 1</h3>
<button id="templButton" data-bind="click: swap">Go to template 2</button>
</script>
<script id="template2" type="text/html">
<h3>Template 2</h3>
<button id="templButton" data-bind="click: swap">Go to template 2</button>
</script>
<div data-bind="template: theTemplate"></div>
<script>
ko.applyBindings({
theTemplate: ko.observable("template1"),
swap: function () {
this.theTemplate("template2");
}
});
</script>
But it change template only one time and only from tempalate1 to the template2. How to make switch to the both templates.
it shoudl be something like
ko.applyBindings({
theTemplate: ko.observable("template1"),
swap: function () {
if (this.theTemplate==template1)
{
this.theTemplate("template2");
}
else
{
this.theTemplate("template1");
}
}
});
But what is this.theTemplate("template2") what operation () making in current context? How to check in what state is theTemplate?
You're just missing a couple things:
To get the value of an observable, you invoke it
The value of the observable is a string, so quote it
So:
if (this.theTemplate() == 'template1') {
ko.applyBindings({
theTemplate: ko.observable("template1"),
swap: function() {
if (this.theTemplate() == 'template1') {
this.theTemplate("template2");
} else {
this.theTemplate("template1");
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script id="template1" type="text/html">
<h3>Template 1</h3>
<button id="templButton" data-bind="click: swap">Go to template 2</button>
</script>
<script id="template2" type="text/html">
<h3>Template 2</h3>
<button id="templButton" data-bind="click: swap">Go to template 2</button>
</script>
<div data-bind="template: theTemplate"></div>

emberjs append works but raises Assertion Failed error

I'm new to ember I am trying to append a template to another and it seems to work but it raises an error, can you please explain why?
The error:
Assertion failed: You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead
This is the code in app.js
App.NewStickie = Ember.View.extend({
click: function(evt){
var stickie = Ember.View.create({
templateName: 'stickie',
content: 'write your notes here'
});
stickie.appendTo('#stickies');
}
});
These are the contents of index.html
<script type="text/x-handlebars">
{{#view App.NewStickie}}
<button type="button" class="btn btn-success">
New
</button>
{{/view}}
{{outlet}}
</script>
<script type="text/x-handlebars" id="index">
<div id="stickies">
{{#each item in model}}
<div class="stickie" contenteditable="true">
{{#view App.DeleteStickie}}
<span class="glyphicon glyphicon-trash"></span>
{{/view}}
<div contenteditable="true">
{{item.content}}
</div>
</div>
{{/each}}
</div>
</script>
<script type="text/x-handlebars" data-template-name="stickie">
<div class="stickie">
{{#view App.DeleteStickie}}
<span class="glyphicon glyphicon-trash"></span>
{{/view}}
<div contenteditable="true">
{{view.content}}
</div>
</div>
</script>
Each view in ember have a template, for example:
foo_view.js
App.FooView = Ember.View.extend({
templateName: 'foo'
})
foo template
<script type="text/x-handlebars" data-template-name="index">
<div id=myFooView>Foo</div>
</script>
You are trying to insert a view inside of other in that way:
App.BarView.create().appendTo('#myFooView')
This isn't allowed. You can use the {{view}} handlebars helper to render a view inside other like that:
foo template
<script type="text/x-handlebars" data-template-name="index">
<div id=myFooView>
Foo
{{view App.BarView}}
</div>
</script>
But I think that you want this working dynamically. So you can use the ContainerView, like described by the error message:
App.StickiesView = Ember.ContainerView.extend({
click: function() {
var stickie = Ember.View.create({
templateName: 'stickie',
content: 'write your notes here'
});
this.pushObject(stickie);
}
})
I see in your code a lot of views with the click event, ember encourage you to use actions, this give more flexibility, error/loading handling etc. I think is a good idea to use it.
I hope it helps
You should probably read this guide that explains that ContainerView is. Also, I don't think it's necessary to create another View to append a template to another template.

Knockoutjs: dynamic content and applyBindings

I am "dynamically" populating my page like this:
<script type="text/html" id="ContainerTemplate">
<span data-bind="template: {
name: contentTemplate,
data: contentData }"></span>
</script>
<script type="text/html" id="fooTemplate">
<span data-bind="text: barAttribute"></span>
</script>
<button data-bind="click: complete">complete</button>
Hello
<span data-bind="template: { name: 'ContainerTemplate', foreach: myContents }"></span>
!
ViewModel:
var viewModel = {
myContents: ko.observableArray([]),
complete: function() {
viewModel.myContents.push({
contentTemplate:'fooTemplate',
contentData:{barAttribute:'world'}});
}
};
ko.applyBindings(viewModel);
A particularity is that template names are dynamic. It seems to work like this (you can try it on http://jsfiddle.net/hPQNx/ ), but I wonder if I'm doing things correctly. Some template features like root or parent don't seem to be working.
Should I manually re-call applyBindings at some point ? I have seen this must be done on the related DOM nodes, but how can I access those nodes in my setup ?
I added a property to your view model and showed how you can add a root property and reference it with $root and $parent can work here in this fiddle.
var viewModel = {
a: ko.observable('foo'),
myContents: ko.observableArray([]),
complete: function() {
viewModel.myContents.push({
contentTemplate: 'fooTemplate',
b: 'goo',
contentData: {
barAttribute: 'world'
}
});
}
};
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.0.0/knockout-min.js"></script>
<script type="text/html" id="ContainerTemplate">
<span data-bind="template: {
name: contentTemplate,
data: contentData }"></span>
</script>
<script type="text/html" id="fooTemplate">
<span data-bind="text: barAttribute"></span>
<div data-bind="text: $root.a"></div>
<div data-bind="text: $parent.b"></div>
</script>
<button data-bind="click: complete">complete</button>
Hello
<span data-bind="template: { name: 'ContainerTemplate', foreach: myContents }"></span>
!

Categories

Resources