button selector binding issue on private / public closure - javascript

I'm creating a set of JavaScript methods that will clone pre-existing HTML. Here is the HTML:
<!DOCTYPE html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- <script src="lib/pm-helpers.js"></script> -->
<script src="lib/pm-ajax-inputs.js"></script>
</head>
<style>
.hidden { display: none; }
</style>
<body>
<script>
jQuery( document ).ready( function() {
/*
* Clone example
* the instance() method takes 3 parameters
* #param: wrapper id or class
* #param: clone group
* #param: action button, image or link; something with a click event ability.
*/
var instance = PM_CONTROLS.MODEL.PROPS.instance( '.first', '.control-group', '#clone' );
instance.bind();
} );
</script>
<ul class='first'>
<li class='control-group'>
<input type="text" name="discover[]" value="" placeholder="info here" />
<input type="button" id="bn-edit" class="green pm-edit" value="edit">
<input type="button" id="bn-delete" class="blue pm-delete" value='delete'>
</li>
</ul>
<ul class='second'>
<li id='control-group2' class='controls '>
<input type="text" name="discover[]" value="" placeholder="info here" />
<input type="button" id="bn-edit1" class="green pm-edit" value="farfenugal">
<input type="button" id="bn-delete1" class="blue pm-delete" value='farfenay'>
</li>
</ul>
<ul id="control-wrapper">
<li class='controls'>
<input type="text" name="discover[]" value="" placeholder="control purpose here" />
<input type="button" id="clone" class="green pm-add" value="add">
</li>
</ul>
<ul id="control-wrapper2">
<li class='controls'>
<input type="text" name="discover[]" value="" placeholder="control purpose here" />
<input type="button" id="clone1" class="green pm-add" value="add">
</li>
</ul>
</body>
Here is the JS:
var PM_CONTROLS = PM_CONTROLS || {};
PM_CONTROLS.createNS = function ( namespace ) {
var nsparts = namespace.split(".");
var parent = PM_CONTROLS;
// include or exclude the root namespace so we strip it if it's in the namespace
if (nsparts[0] === "PM_CONTROLS") {
nsparts = nsparts.slice(1);
}
// if required create a nested namespace by looping through the parts
for (var i = 0; i < nsparts.length; i++) {
var partname = nsparts[i];
// check if the current parent already has the namespace declared
// if it doesn't then create it
if (typeof parent[ partname ] === "undefined") {
parent[partname] = {};
}
// get a reference to the deepest element in the hierarchy
parent = parent[ partname ];
}
// the parent is now constructed with empty namespaces and can be used.
// we return the outermost namespace
return parent;
};
PM_CONTROLS.createNS( 'PM_CONTROLS.MODEL.PROPS');
PM_CONTROLS.createNS( 'PM_CONTROLS.ACTIONS');
PM_CONTROLS.props = null;
PM_CONTROLS.i= 0;
PM_CONTROLS.MODEL.PROPS.instance = function ( wrapper_class_or_id, element_to_clone_id, clone_button_id ) {
var props = {
wrapper : wrapper_class_or_id + PM_CONTROLS.i++
, clone : element_to_clone_id + PM_CONTROLS.i
, button : clone_button_id
};
var bind = function() {
PM_CONTROLS.props = getProps();
return new PM_CONTROLS.ACTIONS.bindAction();
};
var getProps = function() {
return props;
};
return {
bind : bind
, getProps: getProps
};
};
PM_CONTROLS.ACTIONS.clone = function() {
var clone = $( PM_CONTROLS.props.clone ).clone();
$( PM_CONTROLS.props.wrapper ).append( clone );
clone.fadeIn('fast');
};
PM_CONTROLS.ACTIONS.bindAction = function () {
$( PM_CONTROLS.props.button ).on( 'click', '', PM_CONTROLS.ACTIONS.clone() );
//$( '#clone' ).click( PM_CONTROLS.ACTIONS.clone() );
};
So when running the HTML the ul with the class='control-group' is getting loaded into the PM_CONTROLS closures and properties.
Furthermore, the code steps through everything without any errors and the values that eventually get passed to the bindAction() method are correct ( I've hard-coded the selector for debugging purposes in the bindAction code ).
Can you explain why the HTML button with the id='#clone' is not binding a click event for the instance variable that is created?
Your help is appreciated on this one.
Regards,
Steve

Related

Classlist validation for unique selected item

So I'm trying to create a chat application like messenger.
When I press the button, a new conversation should be started. I want to add a list item in my overview bar on the left but there can only be one selected, and that one has the 'history-item-selected' classname. So every new convo gets that classname, while the others ones get another classname to change it's appearance but it won't work.
const newConvoButton = document.getElementById("newmessage");
const addNewConvo = (e) => {
e.preventDefault();
const myMessages = document.getElementById('history');
let newListItem = document.createElement('li');
newListItem.textContent = "user " + Math.floor(Math.random(2 - 100) * 100);
myMessages.appendChild(newListItem);
if (newListItem.classList = 'history-item-selected') {
newListItem.classList.add('history-item-selected');
} else {
newListItem.classList.add('history-item')
};
};
newConvoButton.addEventListener('click', addNewConvo);
<main>
<div id="top">
<span>
<h2>My conversations</h2>
</span>
<button type="submit" id="newmessage">+</button>
</div>
<div id="messagecontainer">
<ul id="history"></ul>
<id id="chatscreen">
<ul id="messages">
<li>yolo</li>
</ul>
<div id="messagebottom">
<input type="text" placeholder="Start met typen" size="28" height="auto"> <button type="submit">Send</button>
</div>
</id>
</div>
</main>
There is a "tautological" way to do what you are trying to do.
var addNewConvo = (e)=> {
var nodes = document.querySelectorAll(".history-item-selected");
nodes.forEach(function(elem) {
this.classList.remove("history-item-selected");
});
e.target.classList.add("history-item-selected");
}
In your CSS, you should have something like
.history-item {
/*Styles for history-item*/
}
.history-item.history-item-selected {
/*Styles for elements with both */
}

How to access knockout $index in javascript

I need to get the $index in a javascript function to implement prev/next buttons for a list of values. The method I found seems cumbersome, perhaps there is a more straightforward way.
Now I do this to get the $index in javascript, then put it in an observable:
<div data-bind="foreach: myarray">
<div data-bind="click: function(data, event){ onclick(data, event, $index()); }"
function onclick(idata, event, index) {
theAppViewModel.choiceindex(index);
On SO I found a small improvement by getting $index from the event:
<div data-bind="foreach: myarray">
<div data-bind="click: onclick"
function onclick(idata, event) {
var context = ko.contextFor(event.target);
theAppViewModel.choiceindex(context.$index());
From a commenter came the method to get the index by searching the array for the selected value, that usually has its own observable, e.g. choice:, like:
var i = TheArray.indexOf(theAppViewModel.choice());
Normally, the length of the array on the page isn't huge, and if it has big objects, you could just search over one of its fields with fun syntax like:
myarray.find(x => x.id === searchvalue);
But I wonder if it isn't possible to access the $index even more directly, without storing in my own observable choiceindex, as the Knockout docs say that $index is already an observable.
Here is a complete sample code to play with:
<!DOCTYPE html>
<html>
<head>
<title>Test Knockout Foreach</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src='https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js'></script>
<style>
.selected {background-color: #f0f0f0;}
</style>
</head>
<body>
<div data-bind="foreach: myarray" style="width: 10em;">
<div data-bind="click: function(data, event){ onclick(data, event, $index()); },
css: { selected: $data == $root.choice() }">
<span data-bind="text: $index"></span>
<span data-bind="text: $data"></span>
</div>
</div>
<input type="button" value="Prev" data-bind="click: onprev" />
<input type="button" value="Next" data-bind="click: onnext" />
<p>
Choice:
<span data-bind="text: choice"></span>
</p>
<p>
Index:
<span data-bind="text: choiceindex"></span>
</p>
<script>
var TheArray = ["apple", "pear", "banana", "coconut", "peanut"];
function onclick(idata, event, index) {
theAppViewModel.choice(idata);
theAppViewModel.choiceindex(index);
//var context = ko.contextFor(event.target);
//theAppViewModel.choiceindex(context.$index());
//theAppViewModel.choiceindex(index);
}
function onprev(idata, event) {
var i = theAppViewModel.choiceindex() - 1;
if (i >= 0) {
theAppViewModel.choice(TheArray[i]);
theAppViewModel.choiceindex(i);
}
}
function onnext(idata, event) {
//var i = theAppViewModel.choiceindex() + 1;
//var dummydata = theAppViewModel.choice();
//var dummy = TheArray.indexOf(dummydata);
var i = TheArray.indexOf(theAppViewModel.choice()) + 1;
if (i < TheArray.length) {
theAppViewModel.choice(TheArray[i]);
theAppViewModel.choiceindex(i);
}
}
function AppViewModel() {
var self = this;
self.myarray = ko.observableArray(TheArray);
self.choice = ko.observable();
self.choiceindex = ko.observable();
}
var theAppViewModel = new AppViewModel();
window.onload = function () {
ko.applyBindings(theAppViewModel);
}
</script>
</body>
</html>
There is no built-in binding to set a viewmodel value from a binding, but it's simple create one to do so:
ko.bindingHandlers.copyIndex = {
init: function (element, valueAccessor, allBindings, vm, bindingContext) {
vm.index = bindingContext.index;
}
};
The use it as follows:
<div data-bind="foreach: myarray">
<div data-bind="copyIndex"></div>
</div>
However, I'd still not recommend this approach, since it ties viewmodel behavior to the presence of specific bindings. Jason Spake's suggestion to use myarray.indexOf($data) (or ko.utils.arrayIndexOf(myarray, $data)) would be more robust.
write 'index' and not 'index()' in the html part.
Try this:
<div data-bind="foreach: myarray" style="width: 10em;">
<div data-bind="click: function(data, event){ onclick(data, event, $index},
css: { selected: $data == $root.choice() }">
<span data-bind="text: $index"></span>
<span data-bind="text: $data"></span>
</div>
</div>

When I reload the page my previous comments disappear - something to do with local storage

Trying to make it so that when I refresh the page the previous comments remain on the page. Not quite sure how to do it. Also was wondering how you would go about making it so that when you click on the namebox you don't have to highlight "name" and then write your name, you can just click and what you write simply replaces the "name".
//Functions for Homepage
function imgUpdate() {
var img = document.getElementById("navImg").alt;
if (img === "Cat Selfie") {
document.getElementById("navImg").src = "foo.jpg";
document.getElementById("navImg").alt = "foo"
}
else {
document.getElementById("navImg").src = "cat-selfie.jpg";
document.getElementById("navImg").alt = "Cat Selfie"
}
}
//Functions for Comments
function clearComment(){
$('#txt1').val(''); //short for getElement when using j query
};
function clearName(){
$('#namebox').val('');
};
function saveComment() {
var ctext = $('#txt1').val();
var cname = $('#namebox').val();
if (cname === 'Name') {cname = 'Anon';}
alert('saveComment cname=' + cname + ' ctext=' +ctext);
var d = Date();
var prevComments = $('#cmtlist').html();
var curComment='<p><span class="cmtname">'+cname+ ':' + '</span>'
+ctext +d+' </p>'; //span = add things to something inline
curComment += prevComments;
$('#cmtlist').empty();
$('#cmtlist').append(curComment);
clearComment();
clearName();
setObject('totCmts', curComment);
}
function fetchComments(){
var inlist=getObject('totCmts');
if(inlist === null){
inlist='';
}
//display the comments
$('#cmtlist').empty();
$('#cmtlist').append(inlist);
}
My Html file
<html>
<head>
<meta charset="utf-8" />
<title>Dubya comments</title>
<link rel="stylesheet" href="homepage.css" type="text/css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="homepage.js"></script>
</head>
<body>
<header id="banner">
</header>
<nav>
<button type="button" onclick="clearComment()">Clear
comment</button>
<button type="button" onclick="saveComment()">Save comment</button>
</nav>
<div id="main">
<div id="dtext">
<h4>Your comment</h4>
<input id="namebox" type="text" maxlength="32" size="20"
value="Name" />
<br />
<textarea id="txt1" class="textbox" rows="6"></textarea>
</div>
<h4>Comments</h4>
<div id="cmtlist"></div>
</div>
</body>
</html>
Jack, you can easily store data in localStorage using global object like this:
// your array with comments
var comments = ["First comment", "Second comment"];
// saving your comments in JSON format
window.localStorage.setItem("comments", JSON.stringify(comments));
// retrieving them
comments = JSON.parse(window.localStorage.getItem("comments"));
You can read more about localStorage on MDN

javascript How to get two toggles on a page to work independently

Hi i currently have two toggles, one is on the sidebar and one is in the main body. They currently work together which is annoying, even though i am using to different scripts. The scripts i am using at the moment for the toggles are almost identical, however, even when using completely different scripts they still work together.
what i mean by work together is when i click the toggle on the main body the side bar toggle reacts.
They are toggles which collapse on oclick.
<script>
var divs = ["Menu", "Add"];
var visibleDivId = null;
function toggleVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
}
function hideNonVisibleDivs() {
var i, divId, div;
for(i = 0; i < divs.length; i++) {
divId = divs[i];
div = document.getElementById(divId);
if(visibleDivId === divId) {
div.style.display = "block";
} else {
div.style.display = "none";
}
}
}
</script>
<script>
$(document).ready(function () {
// set up the click event
$('.body > a').on('click', function(){
$(this).next('div').siblings('div:not(#Menu)').hide("1");
});
// trigger orders which has id francc, not orders // .show("1") goes between $(this).next('div') + .siblings
// if i want a transition
$('#Menu').trigger('click');
// options include >>>, but it's slower // $('a[name="account"]').trigger('click');
});
</script>
<!-- sidebar toggle-->
<script>
var divs = ["Order", "Rest", "Franc"];
var visibleDivId = null;
function toggleVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
}
function hideNonVisibleDivs() {
var i, divId, div;
for(i = 0; i < divs.length; i++) {
divId = divs[i];
div = document.getElementById(divId);
if(visibleDivId === divId) {
div.style.display = "block";
} else {
div.style.display = "none";
}
}
}
</script>
<!-- Change color on click-->
<script>
$(document).ready(function() {
$('.sidebar h3').on('click', function() {
$('.sidebar h3').css('color', 'black');
$(this).css('color', 'red');
});
$('h3#open').trigger('click'); //Your account red on page load
});
</script>
<!--Your account toggle open on load -->
<script>
$(document).ready(function () {
// set up the click event
$('.sidebar > a').on('click', function(){
$(this).next('div').siblings('div:not(#Franc)').hide("1");
});
// trigger orders which has id francc, not orders // .show("1") goes between $(this).next('div') + .siblings
// if i want a transition
$('#francc').trigger('click');
// options include >>>, but it's slower // $('a[name="account"]').trigger('click');
});
</script>
<div class="sidebar">
<!-- Orders toggle-->
<a id="order" class="header" href="#" onclick="toggleVisibility('Order');"><h3 id="orderr">Orders</h3></a>
<div id="Order" style="display: none;">
<div>
<ul class="tabs">
<li id="order" class="Red">Overview</li>
</ul>
</div>
</div>
<!--Restaurant toggle-->
<a id="restt" class ="header"href="#" onclick="toggleVisibility('Rest');"><h3>Your Restaurants</h3></a>
<div id="Rest" style="display: none;"><div>
<ul class="tabs">
<!-- <li id="order" class="rred">restaurant</li>-->
<li id="order" class="rgreen">New restaurant</li>
</ul>
</div>
</div>
<!-- Account toggle-->
<a id="francc" name="account" class ="header" href="#" onclick="toggleVisibility('Franc');"><h3 id="open">Your Account</h3></a>
<div id="Franc" style="display: none;">
<div>
<ul class="tabs">
<li id="order" class="Blue" >Order History</li>
</ul>
</div>
</div>
</div>
<div id=body>
<!-- Menu toggle -->
<div class="container_head"> <!-- red header top of container-->
<a id="Menu" class="header" href="#" onclick="toggleVisibility('Menu');"><h3>Menu Section</h3></a>
</div>
<div id="Menu_form" style="display: none;">
<form id="MenuForm" action ="javascript:void(0);" method="POST">
<!-- <div class="field">-->
<label for="Name">Name</label>
<input type="text" name="Name" id="Name" placeholder="Steaks pattern="[a-zA-Z]"
required tabindex="1">
<br>
<label for="Description">Description</label>
<input type="text" name="Description" id="Description" placeholder="Fresh USDA Choice steaks, seasoned with hickory-smoked sea salt." tabindex="2">
<br>
<div class="field">
<input type="submit" value="Save">
</div>
</form>
</div>
<a id="add_prod" class="header" href="#" onclick="toggleVisibility('Add');"><h3>Orders</h3></a>
<div id="add" style="display: none;">
</div>
Bringing together #j08691 and Leo Farmer's comments, you need to have unique IDs and function names. When you call toggleVisibility(...), it's going to call the second declaration of that method. Also, when you call document.getElementById(...) on something like "order", it's going to stop at the first instance it finds (In your case, the a tag).
Give your functions unique names, give your items unique IDs (if you want them to all do the same thing, you can look at using the same class for each item), and you should be in a better spot.

How to get the Ids of checkbox I've checked?

I tried the below code,
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="http://static.jstree.com/v.1.0pre/jquery.js"></script>
<script type="text/javascript" src="http://static.jstree.com/v.1.0pre/jquery.jstree.js"></script>
</head>
<body>
<div id="jstree_id" class="demo">
<ul>
<li id="asia">
asia
<ul>
<li id="china">
india
</li>
<li id="japan">
japan
</li>
</ul>
</li>
<li id="usa">
usa
</li>
</ul>
</div>
<input type="text" id="com" onKeyUp="bridge('com_url','my_id')" />
<input type="text" id="person" onKeyUp="bridge('prsn_url','my_id')" />
<input type="button" value="click" onClick="bridge('url','my_id');" />
<script type="text/javascript" class="source">
$(function () {
$("#jstree_id").jstree({
"plugins" : [ "themes", "html_data", "checkbox", "sort", "ui" ]
});
});
function bridge(path, tag) {
// path & tag are required one for Ajax functions*
var checked_ids = [];
$("#jstree_id").jstree("get_checked",null,true).each(function () {
checked_ids.push(this.id);
});
var company = $("#com").val() || [];
var person = $("#person").val() || [];
console.log(company+person+checked_ids);
}
</script>
</body>
</html>
The question is:
When I click on the checkbox it returns only the ids Iv'e already checked. How do I get the ids of currently checked checkboxes?
My whole purpose of the code is to search the database against all combination of checkbox tree and text through Ajax.
Instead of using js events, it's best to use the native events supported by jstree:
<body>
<div id="jstree_id" class="demo">
<ul>
<li id="asia">
asia
<ul>
<li id="china">
india
</li>
<li id="japan">
japan
</li>
</ul>
</li>
<li id="usa">
usa
</li>
</ul>
</div>
<input type="text" id="com" onKeyUp="bridge('com_url','my_id')" />
<input type="text" id="person" onKeyUp="bridge('prsn_url','my_id')" />
<input type="button" value="click" onClick="bridge('url','my_id');" />
<script type="text/javascript" class="source">
$(function () {
$("#jstree_id").jstree({
"plugins" : [ "themes", "html_data", "checkbox", "sort", "ui" ]
});
});
$('#jstree_id').bind('change_state.jstree',function(){
bridge('url','my_id');
});
function bridge(path, tag) {
//path & tag are required one for Ajax functions
var checked_ids = [];
$("#jstree_id").jstree("get_checked",null,true).each(function () {
checked_ids.push(this.id);
});
var company = $("#com").val() || [];
var person = $("#person").val() || [];
console.log(company+person+checked_ids);
}
</script>
</body>
</html>
Using the click event directly does not work, as the jstree event which changes the states of the checkboxes fires after the click event fires
function getCheckedIDs()
{
var elements = document.getElementsByTagName("INPUT");
var checkedArray = new Array();
for(var i=0;i<elements.length;i++)
{
if(elements[i].type === 'checkbox' && elements[i].checked)
{
checkedArray.push(elements[i].id);
}
}
return checkedArray;
}
You can call this function onchange of checkboxes.
u can try this
$(document).ready(function() {
var entity=[];
$("input[type='checkbox']").click(function(){
entity = $('input:checkbox:checked[name=checked]').map(function () {
return $(this).attr("id");
}).get();
alert(entity);
});
});

Categories