Knockoutjs binds correctly however href on a tag doesn't redirect to the page - javascript

I have this html:
<ul class="nav nav-tabs ilia-cat-nav" data-toggle="dropdown" data-bind="foreach : Items" style="margin-top:-30px">
<li role="presentation" data-bind="attr : {'data-id' : ID , 'data-childCount' : Children().length}" style="padding-left: 20px; padding-right: 20px; text-align: center; color: white" class="active-li">
<label id="menu1" data-toggle="dropdown" data-bind="text: Name"></label>
<ul class="dropdown-menu" data-bind="foreach: Children" role="menu" aria-labelledby="menu1">
<li role="presentation"><a role="menuitem" data-bind="text: Name, attr: { 'href': Url} "></a></li>
</ul>
</li>
</ul>
That creates my menu on top using knockoutjs, it works perfectly and href attribute on a tag is filled correctly like href="/site/models#{"catId": "76b4a8ed-1350-46af-8184-3b68029cbd22"}" however when i click on the item, it doesn't redirect to new page. my first thought was maybe its because of hash but it wasn't, so i tried to use target attribute for any of the _self and all others it doesn't work. so my next guess was that there is a javascript method overriding this, so far i haven't found anything. so my question is why doesn't it work?
KnockOut ViewModel:
landing.dataModels.Category = function (_id, _categoryTypeId, _name, _description, _parentId, _children) {
var self = this;
this.ID = ko.observable(_id);
this.CategoryTypeId = ko.observable(_categoryTypeId);
this.Name = ko.observable(_name);
this.Description = ko.observable(_description);
this.ParentId = ko.observable(_parentId);
this.Url = ko.computed(function () {
return '/site/models#{"catId": "' + self.ID() + '"}';
});
this.Children = ko.observableArray([]);
this.getChildren = ko.computed(function () {
return self.Children();
});
_.each(_children, function (item) {
self.Children.push(new landing.dataModels.Category(item.ID, item.categoryTypeId, item.Name, item.Description, item.ParentId, item.Children));
});
};
Update
I have to say that when i right-click on the item and open in new window it does work and shows the page, but its not working on direct left click.

Probably the problem is in the quotes in the generated URL:
href="/site/models#{"catId": "76b4a8ed-1350-46af-8184-3b68029cbd22"}"
The value for href is actually "/site/models#{" leaving the rest of the URL as invalid HTML.
You could try to bind to the escaped URL:
this.Url = ko.computed(function () {
return encodeURI('/site/models#{"catId": "' + self.ID() + '"}');
});

Finally i got tired and i just went with a simple jquery click to make it work:
$(document).ready(function () {
setTimeout(function () {
$(document).on("click", ".ilia-catLink", function () {
var a = $(this).attr("href");
window.location = a;
});
}, 100);
It works this way, but i still wonder why wouldn't that href work on itself.

Related

How to make links added from JSON clickable?

I am trying to append links from a JSON file but their onClick is not working.
HTML:
<li class="nav-item dropdown" id = "views">
<a class="nav-link dropdown-toggle" id="view-type" data-toggle="dropdown" data-selected="high_level" aria-haspopup="true" aria-expanded="false">High Level View</a>
<div class="dropdown-menu" aria-labelledby="view-type" style="height: 35vh; overflow: auto;">
<h7 class="dropdown-header">View Type</h7>
<a class="dropdown-item filter-option active" href="javascript:void(0);" id="high_level">High Level View</a>
</div>
</li>
Javascript:
d3.json(theURL, function(error, data) {
if (error) throw error;
var unique = [];
data.forEach(function(e){
if(unique.indexOf(e.segment) == -1){
unique.push(e.segment);
}
});
unique.forEach(d =>
$('#views .dropdown-menu').append(`<a class="dropdown-item filter-option ecodes" href="javascript:void(0);" id="${d.substring(0, 4)}">${d}</a>`)
)
if($('#all').hasClass('active') == true) {
$('.ecodes').remove();
}
});
$('.filter-option').on('click', function() {
let text = $(this).text();
let selected = $(this).prop('id');
$(this).parent().parent().children('a').text(text);
$(this).parent().parent().children('a').data().selected = selected;
filters[$(this).parent().parent().children('a').prop('id').replace('-','_')] = selected;
$.each($(this).parent().children('a'), function(i,d)
$(d).removeClass('active'); });
$(this).addClass('active');
});
Is there something wrong with my code? I cant seem to figure out why my links aren't working. I need onClick for them to have the class active.
You should use the static element as a starter then delegating the dynamic node(child node) inside the on method
$('dropdown-menu').on('click','.filter-option', function() {
let text = $(this).text();
let selected = $(this).prop('id');
$(this).parent().parent().children('a').text(text);
$(this).parent().parent().children('a').data().selected = selected;
filters[$(this).parent().parent().children('a').prop('id').replace('-','_')] = selected;
$.each($(this).parent().children('a'), function(i,d)
$(d).removeClass('active'); });
$(this).addClass('active');
});
You have to delegate the click to the parent element that exists in the page before you inject new links.
jQuery's on method accepts a selector as the second argument so you can update the following line:
$('.dropdown-menu').on('click', '.filter-option', function() {
let text = $(this).text();
let selected = $(this).prop('id');
$(this).parent().parent().children('a').text(text);
$(this).parent().parent().children('a').data().selected = selected;
filters[$(this).parent().parent().children('a').prop('id').replace('-','_')] = selected;
$.each($(this).parent().children('a'), function(i,d)
$(d).removeClass('active'); });
$(this).addClass('active');
});
Read more: http://api.jquery.com/on/#direct-and-delegated-events

Deleting href when clicked on a link (a delete icon) beside it (Javascript help)

I have a link <a href="#"> and beside that there is a delete png icon (which is also <a href="#"> link.
So what I want is, when clicked on that delete icon, the link <a href="#"> should get deleted with a confirmation window.
So far I have got like,
html:
<ul>
<li>link <a class="delete" href="#" data-request="POST" >....</a></li>
</ul>
My javascript for data-request
var join_request = function(evnt){
evnt.preventDefault();
var $a = $(this);
var request = $a.data('request') || 'POST';
if (confirm("Are you sure want to delete it?")) {
$.ajax($a.attr('href'), {
type: request,
context: $a,
success: join_request_success
});
}
return false;
};
var join_request_success = function(data, a, b){
this.trigger('executed');
};
$(document).ready(function(){
$('a[data-request]').bind('click', join_request);
}
This doesn't seem to be working! When I am clicking on the delete icon, it is displaying the confirmation window but not doing anything.
Is there any other simple way of achieving this? If not, can anyone tell me where am I going wrong?
Thanks.
var join_request = function(evnt){
evnt.preventDefault();
var $a = $(this);
var request = $a.data('request') || 'POST';
if (confirm("Are you sure want to delete it?")) {
$.ajax($a.attr('href'), {
type: request,
context: $a,
error: join_request_success
});
}
return false;
};
var join_request_success = function(data, a, b){
this.trigger('executed');
this.prev().remove();
};
$(document).ready(function(){
$('a[data-request]').bind('click', join_request);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul>
<li>link <a class="delete" href="#" data-request="POST" >....</a></li>
</ul>
Note that I had to change success: to error: for demonstration.

Durandal 2.0 - Update the value of an observable in the view

I'm new to Durandal, my question has probably a very simple issue.
I load a list into a dropdown and the current value on the link which display the dropdown,
And the value of the link which display the dropdown is not updated correctly when an other value is selected.
But actually, I can't set the value of the observable in the select function.
View Model
var self = this;
self.system = require('durandal/system');
IPsKeys: ko.observableArray([]),
ipKeys: ko.observable(""),
activate: function (context) {
var that = this;
that.IPsKeys([]);
that.ipKeys("");
return $.when(
service.getIPSbyClientId(context.clientId).then(function (json) {
$.each(json, function (Index, Value) {
var ClientLobUWYear = {
NameLob: Value.LineOfBusiness.Name,
NameUWYear: Value.UnderwritingYear
};
that.IPsKeys().push(ClientLobUWYear);
// HERE MY VALUE IS GOOD UPDATING AND THE BINDING WORK
if (Index=== 0) {
that.ipKeys(ClientLobUWYear);
}
});
})
).then(function () {
//do some other datacontext calls for stuff used directly and only in view1
});
},
select: function (item) {
this.ipKeys = {
IdClient: item.IdClient,
IdLob: item.IdLob,
NameLob: item.NameLob,
NameUWYear: item.NameUWYear
};
/** PROBLEMS HERE **/
/** Uncaught TypeError: undefined is not a function **/
this.ipKeys(ClientLobUWYear);
},
View
<a id="select_lob-UWYear" class="dropdown-toggle" data-toggle="dropdown" href="#">
<span class="controls_value" data-bind="text: ipKeys().NameLob">ALOB</span>
<span class="controls_value" data-bind="text: ipKeys().NameUWYear">AYEAR</span>
</a>
<ul id="dropdown_year" class="dropdown-menu" data-bind="foreach: IPsKeys().sort(sortByLobYear)">
<li>
<a href="#" data-bind="click: $parent.select">
<span class="controls_value" data-bind="text: NameLob">Cargo</span>
<span class="controls_value" data-bind="text: NameUWYear">2014</span>
</a>
</li>
</ul>
Thanks a lot
The way you update an observable is like this:
var someObservable = ko.observable(""); //setting to "";
someObservable("Something else"); //updating to "Something else"
Not like this (which you are doing above)
var someObservable = ko.observable(""); //setting to "";
someObservable = "Something else";
This is overwriting someObservable with a string of value "Something else" and so is no longer an observable which is why it will not update the ui.
[JS Fiddle showing how to set observables.]

How to handle nested menu in knockout viewmodel

I am using knockoutjs in my project. I have a scenario where I have to create a nested menu in my viewmodel, which I did like this:
self.menu = [
{
name: 'Services',
sub: [{ name: 'Service-A' }, { name: 'Service-B' }]
},
// etc
];
self.chosenMenu = ko.observable();
self.goToMenu = function (main, sub) {
var selectedMenu = {
main: main,
sub: sub
};
self.chosenMenu(selectedMenu);
};
My View:
<ul class="nav navbar-nav menuitems col-md-8" data-bind="foreach: menu">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<span data-bind="text: name"></span></a>
<ul class="dropdown-menu" role="menu" data-bind="foreach: sub">
<li>
<a href="javascript:void(0);" data-bind="text: name,
click: function() { $root.goToMenu($parent, $data); }">
</a>
</li>
</ul>
</li>
</ul>
However, I feel that this approach of creating nested menu is not good, because suppose if I want to go on any menu item programmatically then with his approach it is not possible?
Can anybody please suggest me the good approach to handle this kind of scenario?
Make sure each menu item has a unique identifier. For the example data you've given name will suffice, but you may have to add a fullPath property to menu item view models.
Your goToMenu function can now take just one parameter: uniqueMenuIdentifier, and recurse through all menu items to find the correct one, like this:
function findMenuItem(menuList, uniqueMenuIdentifier) {
for (var i = 0; i < menuList.length; i++) {
if (menuList[i].name === uniqueMenuIdentifier) {
return menuList[i];
}
if (!!menuList[i].sub) {
var subItem = findMenuItem(menuList[i].sub, uniqueMenuIdentifier);
if (!!subItem) {
return subItem;
}
}
}
return null;
}
self.goToMenu = function (menuItem) {
var uniqueMenuIdentifier = menuItem.name;
var item = findMenuItem(self.menu, uniqueMenuIdentifier);
self.chosenMenu(item);
}
This allows for a much simpler binding in the anchor tag:
<a href="javascript:void(0);" data-bind="text: name, click: $root.goToMenu">
See this fiddle for a demo.
From this you can also guess that it's even possible to set the chosenMenu directly:
// No longer needed:
//function findMenuItem(menuList, uniqueMenuIdentifier) { }
self.goToMenu = function (menuItem) {
self.chosenMenu(menuItem);
}
See this fiddle for a demo.
I ran into a similar scenario yesterday. You can have a look at my solution on
Is there any knockout plugin for showing a nested context menu?. The main point is that I've used the template binding to be able to construct a hierarchical menu of any depth.

jQuery click function for <ul><li> elements

I have a unordered list looking like this:
<ul id="frozen" data-name="nameOfSelect" class="tagit">
<li class="tagit-choice" tagvalue="2" style="padding-right: 4px;" id="tag-2">
<div class="tagit-label" data-value="2">kázeň</div>
</li>
<li class="tagit-choice" tagvalue="1" style="padding-right: 4px;" id="tag-1">
<div class="tagit-label" data-value="1">žalmxxxx</div>
</li>
</ul>
I need to bind an click function to all of them and get the data of the id="tag-1" to be used in the function.
I have tried this:
$('#[id|="tag"]').each(function(){
var tag = this.attr('id');
var tagID = tag.replace('tag-','');
this.click(function (){
alert('index.php?s=taglist&tag=' + tagID);
//window.location = string;
});
});
However, for some reason it seems that this approach is wrong for the <li> element as I am having problems with the selector (it seems). Maybe I am also missing something stupid... Any ideas?
No need for a loop, jQuery does this internally, and this is a native DOM element, which has an id property, but no attr() method :
$('[id^="tag-"]').on('click', function() {
var tag = this.id,
tagID = tag.replace('tag-', '');
alert('index.php?s=taglist&tag=' + tagID);
});

Categories