Binding to class in knockout.js - javascript

I want to bind class of LI/DIV. I'm using knockout.js. I don't know how to make it works. This is my code:
<div id="users-list2" class="span8">
<div class="tabbable">
<!-- Only required for left/right tabs -->
<ul class="nav nav-tabs" data-bind="foreach: conversations">
<li data-bind="click: function () { $root.tabClick(username); }, attr:{ 'class': cls}" style="float:left">
<a class="user-box-name"
data-bind="text: username, attr:{ 'href':'#'+ username }, event: { contextmenu: $root.closeTab }"></a>
</li>
</ul>
<div class="tab-content" data-bind="foreach: conversations">
<div data-bind="attr:{ 'id': username, 'class': 'tab-pane ' + cls}">
<div id="chat-list" class="span12" data-bind="foreach: messages">
<ul>
<li>
<div class="chat-listitem-username" data-bind="text: username">
</div>
<div class="chat-listitem-message" data-bind="html: content">
</div>
<div class="chat-listitem-timestamp" data-bind="text: timestamp.toLocaleTimeString()">
</div>
</li>
</ul>
</div>
</div>
and viewModel:
chatR.conversation = function (username) {
var self = this;
self.messages = ko.observableArray();
self.username = username;
self.test = function (x) { alert(x.username) };
self.cls = "";
}
I want to change cls to "active" when specific tab is clicked and change all others cls to "". It's not working. What am I doing wrong? Classes like "tabbable" and "nav" are defined by bootstrap.js.
EDIT:
This is how I want to chnage cls:
self.tabClick = function (username) {
self.currentConversation = username;
for (i = 0; i < self.conversations().length; i++) {
if (self.conversations()[i].username == username) {
self.conversations()[i].cls = "active";
}
else {
self.conversations()[i].cls = "";
}
}
}
EDIT2:
Changes from comment work, but I have another problem. Li has class "active" but DIC gets:
<div id="aaa_1" class="tab-pane function d(){if(0<arguments.length)
{if(!d.equalityComparer||!d.equalityComparer(c,arguments[0]))d.H(),c=arguments[0],d.G();return this}b.r.Va(d);return c}"
data-bind="attr:{ 'id': username, 'class':'tab-pane '+cls}">
What is wrong here?

Posting the details as an answer.
First Step was to make the cls property an observable and change the code to and change your code accordingly self.conversations()[i].cls("active"); or self.conversations()[i].cls("");
For the second as in edit.
You need output the value of cls and not cls as a whole
So change this
<div data-bind="attr:{ 'id': username, 'class': 'tab-pane ' + cls}">
to
<div data-bind="attr:{ 'id': username, 'class': 'tab-pane ' + cls()}">

Answer to edit 2: instead of
'tab-pane ' + cls
use
'tab-pane ' + cls()

Knockout has special binding for classes, a css binding (http://knockoutjs.com/documentation/css-binding.html).
Example:
<div data-bind='css: {classname: bla() == "something"}'>...</div>

Related

How can I search for all translate attributes on page and replace their values?

How can I query the entire HTML page for a specific attribute and either remove it or replace the value?
I was thinking something like this (translate being the attribute name):
$('[translate]').remove();
$('[translate]').value('replace the value of the attribute');
Here is an Example:- You can use nativeElement & querySelector` for DOM Manipulation.
app.component.html
<div class="tabs tabsMenu" #tabs>
abc
</div>
<div id="tab-1" class="tab-content rmpm" role="tabpanel">abc</div>
<div id="tab-2" class="tab-content rmpm" role="tabpanel">abc</div>
app.component.ts
#ViewChild('tabs') public tabs;
constructor(private el: ElementRef) {
this.el = el;
}
let tabsEl = this.tabs.nativeElement;
this.removeActive(tabsEl.querySelectorAll('.active'));
this.setActive([
tabsEl.querySelector(`#${id}`)
]);
setActive(elems) {
elems.forEach((el) => {
el.className += ' active';
});
}
removeActive(elems) {
elems.forEach((el) => {
el.className = el.className.replace(' active', '');
});
$(document).ready(function() {
$('a').click(function(v){
var changeVal = "other_val"
$("[translate]").attr("translate",changeVal)
$("[translate]").html(changeVal)
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<div translate="some_val">some_val
</div>
<div translate="some_val">some_val
</div>
Change attr
Hi! This snippet may be helpful for you.

Trying to return to previous page with javascript + html

UPDATE
I solved the problem, it was quite silly, I named the "id" wrong. It was: id="groups_menu_left" when it actually is: id="especies_menu_left".
Sorry to waste your guys's time.
When I hit the button "Voltar" which means "Back" it isn't going back, can anyone help me?
My application is basically a database for shelters, so when people want to adopt a new pet, they can look for the options various shelters have. When choosing the "Species" it shows all the animals in that category, and when you like an animal, you can click on it for more info. But if a person didn't like the specific info for some reason, they can return to look for more animals, and that's where the button "Voltar" is helpful, but it's not working. When I click on it it doesn't do anything. It doesn't show an error when debugging, so my guess is that I'm missing something in the code.
(function($) {
$.extend({
route: function(path) {
var previousUrl = window.location.hash.slice(1);
window.location.hash = '#' + path;
var pathArray = path.split('/');
$('div[id^="template_"]').hide();
$('button[id^="menu_"]').hide();
var routes = [{
id: 1,
name: 'index',
regex: '(index)'
}, // index
{
id: 2,
name: 'register',
regex: '(register)'
}, // register
{
id: 3,
name: 'especies',
regex: '(especies)'
}, // especies
{
id: 4,
name: 'especie_show',
regex: '(especie).*?(\\d+)'
}, // especie/{:id}
{
id: 5,
name: 'animal_show',
regex: '(animal).*?(\\d+)$'
}, // animal/{:id}
];
var route = 0;
var template = null;
$.each(routes, function() {
var test = new RegExp(this.regex);
if (test.test(path)) {
route = this.id;
template = this.name;
}
});
//Logout button
$('#' + template + '_menu_logout').on('click', function() {
removeToken('token');
});
switch (template) {
case 'index':
break;
case 'register':
break;
case 'especies':
setButton('left', template, 'index', 'redirect', null);
$.api.getRecords('especie', null, getToken('token'), populateEspeciesTable);
break;
case 'especie_show':
setButton('left', template, 'especies', 'redirect', null);
setButton('right', template, 'especie/' + pathArray[1] + '/edit', 'redirect', null);
var params = 'filter=id_especie%3D' + pathArray[1] + '&fields=nome_especie';
$.api.getRecords('especie', params, getToken('token'), populateEspecieShowName);
params = 'filter=especie_id_especie%3D' + pathArray[1] + '&fields=nome_animal, notas_animal, foto_animal';
$.api.getRecords('animal', params, getToken('token'), populateEspecieTable);
break;
case 'animal_show':
var animalId = $('#id_animal').val();
setButton('left', template, 'especie/' + animalId, 'redirect', null);
setButton('right', template, 'animal/' + pathArray[1] + '/edit', 'redirect', null);
var params = 'filter=id_animal%3D' + pathArray[1] + '&fields=nome_animal';
$.api.getRecords('animal/' + pathArray[1], null, getToken('token'), populateAnimal);
var urlParts = previousUrl.split('/');
$('#id_animal').val(urlParts[1]);
break;
}
$('#template_' + template).show();
}
});
function setButton(button, page, url, type, func) {
switch (type) {
case 'redirect':
$('#' + page + '_menu_' + button).off().on('click', function() {
$.route(url);
});
break;
}
}
}(jQuery));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="template_especies">
<nav class="navbar navbar-fixed-top df-nav cen col-md-12" role="navigation" style="">
<ul class="nav navbar-nav" style="width: 100%">
<li style="float: none; display: inline-block; position: relative; text-align: center">
<img src="img/icone_ap.png" height="47">
</li>
</ul>
</nav>
<div class="row vert-offset-top-30"></div>
<div class="col-md-2"></div>
<div class="col-md-8">
<img src="img/cao.jpg" width="150" hspace="20"> <img src="img/gato.jpg" width="150">
<table class="table" id="table_especies">
<thead>
<tr>
<td></td>
<td></td>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<footer>
<ul class="nav navbar-nav" style="width: 100%">
<li class="pull-left"><button type="button" id="groups_menu_left" class="btn btn-default btn-menu">Voltar</button></li>
<li class="pull-left"><button type="button" id="groups_menu_logout" class="btn btn-default btn-menu-logout">Sair</button></li>
</ul>
</footer>
<div class="col-md-2"></div>
</div>
Thanks in advance!!!
Try using window.history.back(); and attaching it to the element with onclick="window.history.back();
You can try it below.
<li class="pull-left">
<button type="button" onclick="window.history.back();" id="groups_menu_left" class="btn btn-default btn-menu" >Voltar</button>
</li>
UPDATE: I don't know if I understand your problem but you can try:
<li class="pull-left">
<button type="button" id="groups_menu_left" class="btn btn-default btn-menu" >Voltar</button>
</li>

Using ForEach to bind data to a table

I am just starting to use Knockout so please dont mind my ignorance.
I am trying to use knockout to build a SPA which basically swaps templates and does some data binding to show a list of array (there are many more functions but I will be sticking to the scope of the question here)
When I do a data-bind using a ViewModel property, I get an error saying that property is not defined when I click on the first link "Input Type", which should populate the table with the ParamData. In my case I am facing the below error
"ParamData is not defined"
I have created a JsFiddle: http://jsfiddle.net/sourabhtewari/c8tm1193/3/
The HTML looks like this:
<script id="ParamHomeTmpl" type="text/html">
<section class="alert alert-info">
<div class="panel-heading h3 blackincolor"><i class="fa fa-exclamation-circle redincolor" style="margin-right: 5px"></i>Please Select Parameter Type</div>
<ul class="blackincolor list-group">
<li><a class="list-group-item list-group-item-info" data-bind="click: templateToUse" href="#" id="InputType"><b>Input Type:</b> Gives an Option to Select your Key-Value Pairs.</a></li>
<li><a class="list-group-item list-group-item-success" data-bind="click: templateToUse" href="#" id="ListType"><b>List Type:</b> You can type in a Key and insert a list of values and select one of the values that you created.</a></li>
</ul>
</section>
</script>
<script id="InputTypeTmpl" type="text/html">
<div>
<p>Input Type</p>
</div>
<table id="paramtypeTbl" data-bind="template:{ name: 'paramDataTmpl'}">
</table>
</script>
<script id="ListTypeTmpl" type="text/html">
<div>
<p>ListType</p>
</div>
</script>
<script id="paramDataTmpl" type="text/html">
<div data-bind="foreach: ParamData">
<span></span><span>Products</span>
<table>
<thead>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td data-bind="text: paramKey"></td>
<td data-bind="text: paramValue"></td>
</tr>
</tbody>
</table>
</div>
</script>
<script id="BlankTmpl" type="text/html"></script>
<div class="tab-pane" id="SelectParamType" data-bind="template: { name: 'ParamHomeTmpl' }"></div>
<div class="tab-pane" id="Attributes" data-bind="template: { name: templateToUse }"></div>
And the Javascript:
var templateType = "BlankTmpl";
var Tempdata = ([{
paramKey: "Sourabh",
paramValue: "Tewari"
}]);
var viewModel = {
ParamData: ko.observableArray(Tempdata)
};
viewModel.templateToUse = function (data, event) {
try {
switch (event.target.id) {
case "InputType":
templateType = "InputTypeTmpl";
break;
case "ListType":
templateType = "ListTypeTmpl";
break;
case "FileType":
templateType = "FileTypeTmpl";
break;
case "DataBaseType":
templateType = "DataBaseTypeTmpl";
break;
default:
return "BlankTmpl";
}
} catch (err) {
return "BlankTmpl";
}
ko.applyBindingsToNode(document.getElementById("Attributes"), {
template: {
name: templateType
}
});
};
viewModel.ParamView = function (data, event) {
ko.applyBindingsToNode(document.getElementById("paramtypeTbl"), {
ParamData: ko.observableArray(Tempdata),
template: {
name: ParamView
}
});
};
ko.applyBindings(viewModel);
Appreciate your help!
Your viewmodel for the template should be passed as the third argument to applyBindingsToNode. Also, since your anchor has sub-parts, the target of the click event might not be what you expect. Better to pass the desired template name explicitly.
HTML:
<li><a class="list-group-item list-group-item-info" data-bind="click: templateToUse.bind(0,'InputTypeTmpl')" href="#" id="InputType"><b>Input Type:</b> Gives an Option to Select your Key-Value Pairs.</a></li>
JS:
viewModel.templateToUse = function (name) {
if (typeof name === 'string') templateType = name;
ko.applyBindingsToNode(document.getElementById("Attributes"), {
template: {
name: templateType
}
}, {
ParamData: ko.observableArray(Tempdata)
});
};
Fiddle: http://jsfiddle.net/c8tm1193/5/

Knockout Conditional Tool

I need to add a conditional tool tip based on the menu item name. I am new to knockout and not sure on the best way to approach this.
<div id="pageMenu" data-bind="foreach: Pages">
<div data-bind="visible: $data.accessAllowed() ">
<a data-bind="click: $parent.openPage, css: { 'selected': Selected }"><div data-bind="text: MenuItemName"></div></a>
In this example title depends whether foo and bar have the same text. If you change foo's text to be foo for example the title will be title2
function bla(){
self.text = ko.observable("Some text");
self.bar = ko.observable("bar");
self.foo = ko.observable("bar");
}
ko.applyBindings(new bla());
<p data-bind="text: text,
attr:{
'title': bar() === foo() ? 'title1' : 'title2'
}">
</p>
you can define function in your view model where you can put your condition for showing the tooltip or hide it like this :
function ViewModel(menuItemName) {
......
self.visibleDiv = ko.computed(function () {
//here you have the item that your are displaying.
//So put here your logic and then
//you should return false or true
.......
});
}
then in your html
<div class="editor-label" data-bind="text: MenuItemName,visible: $root.visibleDiv(MenuItemName)">
This is should be what you are looking for.
<div id="pageMenu" data-bind="foreach: Pages">
<div data-bind="visible: $data.accessAllowed() ">
<a data-bind="click: $parent.openPage, css: { 'selected': Selected }">
<div data-bind="attr : {'title' : ($data.MenuItemName() == 'criteria'? 'tooltip1' : 'tooltip2')} "></div>
</a>
</div>
</div>
I hope it helps.

Keep track of tabs with knockoutjs + twitter bootstrap

I'm trying to keep track of the selected tab in the view model but I can't seem to make it work.
In the following code when you click a tab the header will update correctly but the content of the tab is not displayed. If you remove , click: $parent.selectSection then the contents are shown but the header does not update.
Now if you remove the data-bind="css: { active: selected }" from the li then it seems to work when you click the tabs but the button to select the second tab doesn't.
How can I make this work?
See: http://jsfiddle.net/5PgE2/3/
HTML:
<h3>
<span>Selected: </span>
<span data-bind="text: selectedSection().name" />
</h3>
<div class="tabbable">
<ul class="nav nav-tabs" data-bind="foreach: sections">
<li data-bind="css: { active: selected }">
<a data-bind="attr: { href: '#tab' + name }
, click: $parent.selectSection" data-toggle="tab">
<span data-bind="text: name" />
</a>
</li>
</ul>
<div class="tab-content" data-bind="foreach: sections">
<div class="tab-pane" data-bind="attr: { id: 'tab' + name }">
<span data-bind="text: 'In section: ' + name" />
</div>
</div>
</div>
<button data-bind="click: selectTwo">Select tab Two</button>
JS:
var Section = function (name) {
this.name = name;
this.selected = ko.observable(false);
}
var ViewModel = function () {
var self = this;
self.sections = ko.observableArray([new Section('One'),
new Section('Two'),
new Section('Three')]);
self.selectedSection = ko.observable(new Section(''));
self.selectSection = function (s) {
self.selectedSection().selected(false);
self.selectedSection(s);
self.selectedSection().selected(true);
}
self.selectTwo = function() { self.selectSection(self.sections()[1]); }
}
ko.applyBindings(new ViewModel());
There are several ways that you can handle this either using bootstrap's JS or by just having Knockout add/remove the active class.
To do this just with Knockout, here is one solution where the Section itself has a computed to determine if it is currently selected.
var Section = function (name, selected) {
this.name = name;
this.isSelected = ko.computed(function() {
return this === selected();
}, this);
}
var ViewModel = function () {
var self = this;
self.selectedSection = ko.observable();
self.sections = ko.observableArray([
new Section('One', self.selectedSection),
new Section('Two', self.selectedSection),
new Section('Three', self.selectedSection)
]);
//inialize to the first section
self.selectedSection(self.sections()[0]);
}
ko.applyBindings(new ViewModel());
Markup would look like:
<div class="tabbable">
<ul class="nav nav-tabs" data-bind="foreach: sections">
<li data-bind="css: { active: isSelected }">
<a href="#" data-bind="click: $parent.selectedSection">
<span data-bind="text: name" />
</a>
</li>
</ul>
<div class="tab-content" data-bind="foreach: sections">
<div class="tab-pane" data-bind="css: { active: isSelected }">
<span data-bind="text: 'In section: ' + name" />
</div>
</div>
</div>
Sample here: http://jsfiddle.net/rniemeyer/cGMTV/
There are a number of variations that you could use, but I think that this is a simple approach.
Here is a tweak where the active tab used the section name as a template: http://jsfiddle.net/rniemeyer/wbtvM/

Categories

Resources