Change template dynamic - javascript

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>

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>

Kendo MVVM - template not updating

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>

Code mirror not working with angular js binding variable

Html:
<body ng-app ng-controller="OrderFormController">
<!--<h1 class="errorHeader">List of Classes</h1>-->
<header>
<div class="container">
<div id="branding">
<h1>Apex <span class="highlight"> Editor </span> </h1>
</div>
</div>
</header>
<div class="col-md-12 col-lg-12">
<div class="panel with-nav-tabs panel-default">
<div class="panel-heading">
<ul class="nav nav-tabs">
<li class="active">Apex Editor</li>
</ul>
</div>
<div class="panel-body">
<div>
<input type="text" name="apexClass" id="autocomplete" placeholder="Type the name of the Apex class you want to edit"/>
</div>
<div class="btn-group-vertical" style="padding: 1%">
<button type="button" class="btn btn-primary" id="editBtn">Edit</button>
</button>
</div>
<div class="tab-content" align="left">
<div id='error' style='display:none'>{{apexClassWrapperError.message}}</div>
<div>{{apexClassWrapper.name}}</div>
<img src="../img/ajax-loader.gif" id="loaderImage" style='display:none'>
<form>
<textarea ng-model="apexClassWrapper.body" id="code" name="code" readonly="true" >{{apexClassWrapper.body}}</textarea>
</form>
</div>
<button type="button" class="btn btn-primary" id="saveBtn" ng-click="postdata(apexClassWrapper)">Save</button>
</div>
</div>
</div>
<script src="../js/makeEditable.js"></script>
<script>
$(function() {
var editor = CodeMirror.fromTextArea(document.getElementById("code"),{
linenumber : true,
matchBrackes: true,
mode: "text/x-apex"
})
});
</script>
<footer>
<p>Web based Apex Editor</p>
<p>Developed By - Nagendra Kumar Singh</p>
</footer>
</body>
CSS and JS files included at top:
<script src="../js/codemirror.js"></script>
<script src="../js/apex.js"></script>
<script src="../js/matchbrackets.js"></script>
<link href="../css/codemirror.css" rel="stylesheet"/>
The controller is a simple one fetching the class through a RESTApi.
function OrderFormController($scope, $http) {
$('#autocomplete').autocomplete({
type: 'POST',
serviceUrl: 'http://localhost:8989/getSuggestion',
onSelect: function (suggestion) {
console.log('suggestion.value -> '+suggestion.value);
var data = {
apexClassName:suggestion.value
};
var config = {
params: data
};
$('#loaderImage').show();
$http.get("http://localhost:8989/getApexBody",config).then(function (response) {
$scope.apexClassWrapper = response.data;
$('#loaderImage').hide();
});
}
});
};
But I can only see {{apexClassWrapper.body}} in my text area, I dont see the real code when using CodeMirror, If I remove code mirror , I can see the class, but I cannot figure out a way to show the body with CodeMirror included.
There are no errors in console log and all the JS and CSS files are loaded perfectly. Please help.
Ok, So I think I may have figured it out. What I did is I set a timeout for the codemirror code to run as follows in the js file and removed it from the index.html.
$('#loaderImage').show();
$http.get("http://localhost:8989/getApexBody", config).then(function (response) {
$scope.apexClassWrapper = response.data;
$('#loaderImage').hide();
if(globalEditor) {
globalEditor.toTextArea();
}
setTimeout(function (test) {
var editor = CodeMirror.fromTextArea(document.getElementById('apexBody'), {
lineNumbers: true,
matchBrackets: true,
mode: "text/x-apex"
});
globalEditor = $('.CodeMirror')[0].CodeMirror;
}), 2000
});
The only issue in this answer is that, it creates multiple code editor window when I try to load different classes. How can I resolve that?
So finally got it working, defined a global variable and using the method toTextArea

Knockout.js dynamically selecting template error: "Cannot find template with ID''"

My target is to show "noSets" template if observableArray length less 0 and render template with item details - "showSets", if observableArray length greater 0. I'd like to use templates for this purpose, but FireBug show error: Cannot find template with ID "templatename".
Here is ViewModel:
function SetsViewModel() {
var self = this;
self.usersets = ko.observableArray();
self.getTemplate = function () {
return self.usersets().length > 0 ? "showSets" : "noSets";
}
}
$(document).ready(function () {
ko.applyBindings(new SetsViewModel(), document.getElementById('user_sets'));
});
And here is HTML markup:
<div data-bind="template: { name: $root.getTemplate, foreach: usersets }" id="user_sets">
<script type="text/html" id="noSets">
<p>You do not have items yet.</p>
</script>
<script type="text/html" id="showSets">
<div class="block">
<input type="hidden" data-bind="value: $data.SetId" />
<div class="fav" data-bind="css: { fullop: $data.IsFavorite == true }">
<img alt="" src="img/fav.png" data-bind="click: $root.setFavorite">
</div>
<div>
<img alt="" data-bind="attr: { src: $data.SetImg }">
</div>
<div class="txt">
<h3 data-bind="text: $data.SetName, click: $root.go"></h3>
<p><span data-bind="text: $data.ItemsNumber + ' вещей,'"></span><span data-bind=" text: ' общая цена ' + $data.SetPrice + ' руб'"></span></p>
</div>
</div>
</script>
</div>
How can I fix it?
You can declare the templates outside the div that you're binding to as a work around. As #JeffMercado states:
The actual problem was that since the user_sets uses a template binding, the body is discarded (and the templates along with it)
function SetsViewModel() {
var self = this;
self.usersets = ko.observableArray([{SetId: 1, SetName: 'Name 1'}]);
self.getTemplate = function () {
return self.usersets().length > 0 ? "showSets" : "noSets";
}
}
$(document).ready(function () {
ko.applyBindings(new SetsViewModel(), document.getElementById('user_sets'));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script type="text/html" id="noSets">
<p>You do not have items yet.</p>
</script>
<script type="text/html" id="showSets">
<div class="block">
<input data-bind="value: $data.SetId" />
<div class="txt">
<h3 data-bind="text: 'Set name:' + $data.SetName"></h3>
</div>
</div>
</script>
<div data-bind="template: { name: getTemplate, foreach: usersets }" id="user_sets">
</div>
I think named templates are potentially the wrong approach to this specific issue - they're more designed for when you want a different template for each item, which isn't the case here. Instead, it would be more appropriate to show an entirely different div when there are 0 items:
<div data-bind="visible: usersets().length == 0">
You have no sets
</div>
<div data-bind="visible: usersets().length > 0, foreach: usersets" id="user_sets">
<div class="block">
<input type="hidden" data-bind="value: $data.SetId" />
<div class="fav" data-bind="css: { fullop: $data.IsFavorite == true }">
<img alt="" src="img/fav.png" data-bind="click: $root.setFavorite">
</div>
<div>
<img alt="" data-bind="attr: { src: $data.SetImg }">
</div>
<div class="txt">
<h3 data-bind="text: $data.SetName, click: $root.go"></h3>
<p><span data-bind="text: $data.ItemsNumber + ' вещей,'"></span><span data-bind=" text: ' общая цена ' + $data.SetPrice + ' руб'"></span></p>
</div>
</div>
</div>

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