Execute function with onShow with Materialize doesnt work - javascript

I'm trying to call a function when the tab is changed. Nothing is happening though, does someone see my mistake?
V1:
var elem = $('.tabs')
var options = { onShow: tabChange}
var init_tabs = M.Tabs.init(elem, options);
var instance_tabs = M.Tabs.getInstance(elem);
function tabChange() {
console.log("tab has changed");
}
V2:
document.addEventListener("DOMContentLoaded", function () {
var elem = document.getElementById("periodselector");
var options = { onShow: tabChange }
var init_tabs = M.Tabs.init(elem, options);
});
function tabChange() {
console.log("tab has changed");
}
here the HTML:
<div class="card-tabs">
<ul class="tabs tabs-fullwidth " id="periodselector">
<li class="tab col s3 "><a id="daySelector" class=" " href="#DayTab">Tag</a> </li>
<li class="tab col s3 "><a id="monthSelector" class=" " href="#MonthTab">Monat</a> </li>
<li class="tab col s3 "><a class=" " href="#YearTab">Jahr</a> </li>
</ul>
</div>

On the elem var you should put the javascript object instead of the jQuery one.
From materialize doc:
var instance = M.Tabs.init(el, options);
// Or with jQuery
$(document).ready(function(){
$('.tabs').tabs();
});
Try var elem = $('.tabs')[0] or var elem = $('.tabs').eq(0)
I have not tested this but I believe it will fix your problem

Related

how to render appendChild Js without duplicate

I am a new learning JS. Who can help me complete this code. I have 2 problem:
render child Node user Chat when click without duplicate
how to remove child Node user when close chat window
full code is here: Jsfiddle
// event handling when click
handleEvents: function () {
let _this = this;
userChatList.onclick = function (e) {
const userNode = e.target.closest(".user-chat__item");
if (userNode) {
userIndex = Number(userNode.getAttribute("user-num"));
_this.renderUserChat(userIndex);
const getChatWithItems = document.querySelectorAll(".chat-with__item");
getChatWithItems.forEach(item => {
item.onclick = function(e){
const itemNode = e.target.closest(".chat-with__top i");
if(itemNode){
chatWithList.removeChild(chatWithItem);
}
}
})
}
}
},
//render user chat with someone
renderUserChat: function (num) {
// console.log(userIndex);
chatWithItem = document.createElement("li");
chatWithItem.classList.add("chat-with__item");
chatWithItem.setAttribute('user-num', num);
chatWithItem.innerHTML = `
<div class="chat-with__top">
<div class="chat-with__img">
<img src="${this.users[num].img}" alt="${this.users[num].name}">
<span class="user__status ${this.users[num].status}"></span>
</div>
<p class="chat-with__name">${this.users[num].name}</p>
<i class="fa-solid fa-xmark"></i>
</div>
<div class="chat-with__body">
<ul class="chat__text">
<li class="chat-text__user">Hey. 👋</li>
<li class="chat-text__user user__chatting">I am here</li>
<li class="chat-text__user user__chatting">What's going on?</li>
<li class="chat-text__user">Have you finished the "project 2" yet?</li>
<li class="chat-text__user user__chatting">I have been fixed bugs</li>
<li class="chat-text__user">OK.</li>
</ul>
</div>
<div class="chat-width__footer">
<i class="fa-solid fa-image"></i>
<i class="fa-solid fa-folder"></i>
<div class="chat-width__input">
<input type="text" id="send-sms" name="send SMS" placeholder="...">
</div>
<i class="fa-solid fa-paper-plane-top"></i>
</div>
`
chatWithList.appendChild(chatWithItem);
},
<ul class="chat-with__list">
</ul>
I have not still known how to solve it, up to now
Just keep track which chat windows are opened in an object.
To give you basic idea of the concept:
// storage for opened chat windows
// this variable must be accessible by event handlers
const openedChats = {};
In chat opened event handler:
if (openedChats[userId]) //check if chat already opened
return;
const chatWithItem = document.createElement("li");
...
openedChats[userId] = chatWithItem; //store window
chatWithList.appendChild(chatWithItem); //show window
In chat close event handler:
const chatWithItem = openedChats[userId]; // get opened chat
if (chatWithItem)
{
chatWithItem.parentNode.removeChild(chatWithItem); // destroy window
delete openedChats[userId]; // remove window
}
If you need to get list of all userIds that have opened chat windows, use:
const openedChatsIds = Object.keys(openedChats);
Finnaly I find the way to code. This is my way
handleEvents: function () {
let _this = this;
let currentChat = [];
userChatList.onclick = function (e) {
const userNode = e.target.closest(".user-chat__item");
if (userNode) {
userIndex = Number(userNode.getAttribute("user-num"));
// get value 'userIndex' for currentChat array
function getCurrentChat(arr, index) {
arr.push(index);
}
// check value userIndex in a currentChat array
function checkCurrentChat(arr, index) {
if (arr.indexOf(index) < 0) {
getCurrentChat(currentChat, userIndex);
return true;
} else {
return false;
}
}
let isExisted = checkCurrentChat(currentChat, userIndex);
// console.log(isExisted);
if (isExisted) {
_this.renderUserChat(userIndex);
}
const getChatWithItems = chatWithList.querySelectorAll(".chat-with__item");
getChatWithItems.forEach( function(item) {
item.onclick = function (e) {
const closeChat = e.target.closest(".chat-with__top i");
if(closeChat){
const getNum = Number(closeChat.parentElement.getAttribute("user-num"));
chatWithList.removeChild(item);
const findNum = currentChat.indexOf(getNum);
currentChat.splice(findNum, 1);
}
}
})
}
}
}
inside, i add an attribute to get number (userIndex):
<div class="chat-with__top" user-num ="${num}">
if you use second .parentElement, it will ok.
closeChat.parentElement.parentElement.getAttribute("user-num")

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

Filter list using jQuery

I have a JS code that filters the list with an input field. Currently, the filter is a case sensitive. For example, if you have "item1" you have to type the exact word to filter.
$(function(){
$('input.search').keyup(function(){
var searchText = $(this).val();
$('ul.tabs-menu > li').each(function(){
var currentLiText = $(this).text(),
showCurrentLi = currentLiText.indexOf(searchText) !== -1;
$(this).toggle(showCurrentLi);
});
});
});
Is there any way to optimize it?
Here's a link: http://jsfiddle.net/EFTZR/897/
You can convert the items to lowerCase before comparing like this
$(function() {
$('input.search').keyup(function() {
var searchText = $(this).val();
$('ul.tabs-menu > li').each(function() {
var currentLiText = $(this).text(),
showCurrentLi = currentLiText.toLowerCase().indexOf(searchText.toLowerCase()) !== -1;
$(this).toggle(showCurrentLi);
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" class="search" />
<ul class="tabs-menu" id="category1">
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ul>
<ul class="tabs-menu">
<li>item27</li>
<li>item28</li>
</ul>
I add some visual feedback to see what you are looking for in your list (with the same code as the other anwser for the searching function) and change your item list to see it better.
$(function() {
$('input.search').keyup(function() {
var searchText = $(this).val().trim();
$('ul.tabs-menu > li').each(function() {
var currentLiText = $(this).text(),
showCurrentLi = currentLiText.toLowerCase().indexOf(searchText.toLowerCase()) !== -1;
$(this).toggle(showCurrentLi);
$(this).html(currentLiText.replace(searchText, "<span class='bold'>" + searchText + "</span>"))
});
});
});
.bold {
font-weight: bold;
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" class="search" />
<ul class="tabs-menu" id="category1">
<li>first item</li>
<li>second item</li>
<li>one more item</li>
</ul>
<ul class="tabs-menu">
<li>item test</li>
<li>check item</li>
</ul>
Here is a clean and optimized way to do that ( It is case-insensitive ):
$(function(){
var timer;
function search( searchText ) {
$('ul.tabs-menu > li').each(function(){
var $this = $(this),
currentLiText = $this.text().trim().toLowerCase(),
showCurrentLi = currentLiText.indexOf( searchText ) !== -1;
$this.toggle( showCurrentLi );
});
}
$('input.search').keyup(function(){
var searchText = $(this).val().trim().toLowerCase();
// Checks the value of searchText.
if (searchText) {
// Clears the timer.
if ( timer ){
clearTimeout(timer);
}
// Gives the user 1 second to finish typing.
timer = setTimeout( search.bind(this, searchText ), 1000 );
}
});
});
I hope you like it : JSFiddle

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

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.

Knockout foreach binding not working for me [duplicate]

This question already has an answer here:
Knockout observableArray not updating
(1 answer)
Closed 9 years ago.
My observablearrary "assignedbranches" contains objects when I run this page. But a that has foreach binding to the array is completely empty. Why?
var branchAssignment = function (data) {
this.branchNumber = data.BranchNumber;
this.branchName = data.BranchName;
this.branchlabel = data.BranchLabel;
}
var AppViewModel = function() {
var me = this;
me.assignedbranches = ko.observableArray([]);
me.LoadBranchAssignments = function () {
$.getJSON("api/branchassignments", function (data) {
var sorted = _.sortBy(data, function (b) {
return b.BranchName;
});
$.each(sorted, function (key, val) {
me.assignedbranches().push(new branchAssignment(val));
});
});
};
me.selectBranch = function (data, e) {
console.log(data);
};
me.selectedBranch = ko.observable("Baton Rouge (4001)");
};
var appv = new AppViewModel;
ko.applyBindings(appv);
HTML
<ul class="nav navbar-nav">
<li class="dropdown">
<span data-bind="text: selectedBranch()"></span> <b class="caret"></b>
<ul class="dropdown-menu" data-bind="foreach: assignedbranches ">
<li>
</li>
</ul>
</li>
</ul>
SAMPLE branchAssignment objects
[{"branchNumber":"4042","branchName":"Albuquerque","branchlabel":"Albuquerque (4042)"},{"branchNumber":"4006","branchName":"Alexandria","branchlabel":"Alexandria (4006)"},{"branchNumber":"1118","branchName":"Arden","branchlabel":"Arden (1118)"},{"branchNumber":"1113","branchName":"Ashland","branchlabel":"Ashland (1113)"},{"branchNumber":"4019","branchName":"Atlanta","branchlabel":"Atlanta (4019)"},{"branchNumber":"4030","branchName":"Austin","branchlabel":"Austin (4030)"},{"branchNumber":"1054","branchName":"Bakersfield","branchlabel":"Bakersfield (1054)"},{"branchNumber":"1115","branchName":"Baltimore","branchlabel":"Baltimore (1115)"},{"branchNumber":"4001","branchName":"Baton Rouge","branchlabel":"Baton Rouge (4001)"}]
Try:
me.assignedbranches.push(new branchAssignment(val));
instead of:
me.assignedbranches().push(new branchAssignment(val));

Categories