google closure tool combo box get model - javascript

How to get object from select combomenuitem...?i tried e.target.getMenu().getModel()
</html>
<head>
<title>goog.ui.ComboBox</title>
<script src="closure-library/closure/goog/base.js"></script>
<script>
goog.require('goog.events');
goog.require('goog.ui.ComboBox');
goog.require('goog.dispose');
goog.require('goog.dom');
var test;
</script>
<style>
html, body {
overflow:hidden;
margin: 0;
padding: 5px;
}
#c {
margin-bottom: 10px;
font-size: small;
}
/* Size the combobox so that it is sufficiently small to demonstrate the menu
being positioned to left-align with the control. */
.goog-combobox input {
width: 100px;
}
fieldset {
display: inline-block;
margin: 10px;
text-align: initial;
}
</style>
</head>
<body>
<div id="c">cb.value = '<span id="v"></span>'</div>
<fieldset style="float:left">
<legend>LTR</legend>
<div class="combo"></div>
</fieldset>
<script type="text/javascript">
function createTestComboBox() {
var cb = new goog.ui.ComboBox();
cb.setUseDropdownArrow(true);
cb.setDefaultText('Select a folder...');
cb.addItem(new goog.ui.ComboBoxItem('Inbox',{"a":1}));
cb.addItem(new goog.ui.ComboBoxItem('Bills & statements',{"b":2}));
cb.addItem(new goog.ui.ComboBoxItem('Cal alumni',{"c":3}));
cb.addItem(new goog.ui.ComboBoxItem('Calendar Stuff',{"d":4}));
cb.addItem(new goog.ui.ComboBoxItem('Design',{"e":5}));
cb.addItem(new goog.ui.ComboBoxItem('Music',{"f":6}));
cb.addItem(new goog.ui.ComboBoxItem('Netflix',{"g":7}));
cb.addItem(new goog.ui.ComboBoxItem('Personal',{"h":8}));
cb.addItem(new goog.ui.ComboBoxItem('Photos',{"i":9}));
cb.addItem(new goog.ui.ComboBoxItem('Programming languages',{"j":10}));
return cb;
}
var controls = [];
var containerEls = goog.dom.getElementsByClass(goog.getCssName('combo'));
for (var i = 0; i < containerEls.length; i++) {
var cb = createTestComboBox();
cb.render(containerEls[i]);
goog.events.listen(cb, 'change', handleChangeEvent);
controls.push(cb);
}
function handleChangeEvent(e) {
test=e;
goog.dom.setTextContent(document.getElementById('v'), e.target.getValue());
}
window.onbeforeunload = function() {
goog.disposeAll(controls);
};
</script>
</body>
</html>

You can use getModel which is defined in goog.ui.component and it should be available to ComboBoxitem thru Prototype Inheritance
goog.Disposable >> goog.events.EventTarget >> goog.ui.Component >> goog.ui.Control >> goog.ui.MenuItem >> goog.ui.ComboBoxItem
goog.ui.Component.prototype.getModel = function() {
return this.model_;
};
https://code.google.com/p/closure-library/source/browse/closure/goog/ui/component.js
Documentation - http://docs.closure-library.googlecode.com/git/class_goog_ui_ComboBoxItem.html [ find GetModel ]

In the example code the event listener is attached to the ComboBox, can't find any method of getting the currently selected ComboBoxItem and that's were the model was attached to. So the question is: "How to get access to the ComboBoxItem when attaching change event on the Combobox?" I would expect index or selectedItemIndex or something like that.
goog.events.listen(cb, 'change', handleChangeEvent);
// inside event handler
e.target===this;//true
//second item was clicked:
this === cb;//true
cb.getItemAt(1).getValue();//prints the model object
// but ComboBox has no selectedItemIndex
// or something helpful to get the ComboBoxItem
It would be helpful if they could provide a working example in either the demo's or unit tests, more people would be able to use it. As it is now it's very hard to figure out this mostly undocumented library.

Related

javascript unbind event not unbinding even though it fired

I have some code that when called inside an object, binds an element on the page to a click. When I press a start button again, the elements are updated and I'm adding an event listener for click again. I'm unbinding the event listener prior to adding the even listener again, it fires 10 times to unbind... and then I bind, and it fires 10 times for the binding to be readded... BUT. when I inspect the element, or click the element, it fires twice. If I hit start again, it now fires three times...
card.clickFn = function() {
if(Game.cardsClickedHistory.length<2 && Game.status==1){
card.element.style.backgroundImage = card.image;
Game.cardClicked(card); // notify a card clicked
}
}
card.element.removeEventListener("click", card.clickFn);
card.element.addEventListener("click", card.clickFn);
Repeatable examples
<!DOCTYPE html>
<html>
<head>
<title></title>
<style>
.card {width: 200px; height: 200px; background: red; margin: 10px;}
</style>
</head>
<body>
<div id="cards">
<div class="card"></div>
<div class="card"></div>
</div>
<button id="rebind">REBIND</button>
<script>
var Card = function(element){
var card = this;
card.element = element;
card.clickFn = function(){
console.log("Clicked card");
}
card.element.removeEventListener("click", card.clickFn);
card.element.addEventListener("click", card.clickFn);
}
var CardFactory = function()
{
var cf = this;
cf.cardDivs = document.getElementsByClassName("card");
cf.build = function(){
for(var i=0;i<cf.cardDivs.length; i++)
{
new Card(cf.cardDivs[i]);
}
}
}
var oCF = new CardFactory();
oCF.build();
document.getElementById("rebind").addEventListener("click", oCF.build)
</script>
</body>
</html>
When you instantiate Card object by calling constructor new Card(cf.cardDivs[i]); , the constructor create new function that is not previous function in last construction. Therefore when it tries to remove listener, obviously can not find the previous listener. To Avoid this, you could set a static variable (listeners) that stores bound listeners. Then on next cal of build() function easily can find exact recorded previous bound function as listener. I added a little bit features in your code that it works.
<!DOCTYPE html>
<html>
<head>
<title></title>
<style>
.card {width: 200px; height: 200px; background: red; margin: 10px;}
</style>
</head>
<body>
<div id="cards">
<div class="card"></div>
<div class="card"></div>
</div>
<button id="rebind">REBIND</button>
<script>
var Card = function(element){
var card = this;
card.element = element;
card.clickFn = function(){
console.log("Clicked card");
}
var listener=Card.listeners.filter(function(lis){ return lis.ele===element })[0];
if(listener!==undefined){
card.element.removeEventListener("click", listener.func);
Card.listeners=Card.listeners.filter(function(lis){return lis.ele!==element}); // remove previous listener record
}
card.element.addEventListener("click", card.clickFn);
Card.listeners.push({ele:element,func:card.clickFn}); // add record of listener
}
Card.listeners=[]; //static member
var CardFactory = function()
{
var cf = this;
cf.cardDivs = document.getElementsByClassName("card");
cf.build = function(){
for(var i=0;i<cf.cardDivs.length; i++)
{
new Card(cf.cardDivs[i]);
}
}
}
var oCF = new CardFactory();
oCF.build();
document.getElementById("rebind").addEventListener("click", oCF.build)
</script>
</body>
</html>

How to assign new class after a button/link is clicked(JavaScript)

I'm trying to add new CSS class to HTML body but only after a button/link is clicked. I have included the code along with some errors information.
I have already created a function that can trigger an alert after the button/link is clicked. it's working perfectly but the ".classList.add " method/option is not taking any effects.
<html>
<head>
<style>
.addBGoverlay {background-color: gray;}
.bG {background-color: white;}
</style>
</head>
<body class="BG">
<a class="dash-menu mega-menu-link " role="button" href="#"><span class="mega-indicator"> navButtn</span></a>
<script type="text/javascript">
var X = document.getElementsByClassName('dash-menu');
var xLength = X.length;
var bg = document.getElementsByTagName('body');
function startAction() {
alert('This a popUp');
bg.classList.add("addBGoverlay");
}
for (var i = 0; i < xLength; i++) {
X[i].addEventListener('click', startAction, false);
}
</script>
</body>
</html>
when I inspect it in chrome it gives me an error "Uncaught TypeError: Cannot read property 'add' of undefined
at HTMLAnchorElement.startAction" and the below line is highlited in yellow color "bg.classList.add("addBGoverlay");"
getElementsByTagName() method will give you a collection of DOM elements. Since this collection don't have a classList property it will fail.
You can fix it by using the below code
bg[0].classList.add("addBGoverlay");
You can also use document.body instead of document.getElementsByTagName('body'). First one (document.body) give you the body object and second one will give you a collection object
For switch to previous state
Approach 1
function startAction() {
let body = document.body ;
if(body.classList.contans("addBGoverlay")){ // body.classList.contans() method will give a Boolean return value
body.classList.remove("addBGoverlay");
}else{
body.classList.add("addBGoverlay");
}
}
Approach 2
var hasBGOverlay = false;
var body = document.body ;
function startAction() {
if(hasBGOverlay){
body.classList.remove("addBGoverlay");
}else{
body.classList.add("addBGoverlay");
}
hasBGOverlay = !hasBGOverlay; // In each call state variable value will update with inverse value
}
Hope this helps
Try with Add ID attribute to body tag.
ie:
<body class="bg" id="dg_body">
js
var bg = document.getElementById('dg_body');
and update css order :
.bG {background-color: white;}
.addBGoverlay {background-color: gray;}
will work.
Change your code from :
bg.classList.add("addBGoverlay");
To:
bg.className += "addBGoverlay";
Hope it helps!
Enclosing it under window.load should solve it as it ensures that the DOM is ready before you try to fetch the elements.
window.onload(function() {
var X = document.getElementsByClassName('dash-menu');
var xLength = X.length;
var bg = document.getElementsByTagName('body');
function startAction() {
alert('This a popUp');
bg.classList.add("addBGoverlay");
}
for (var i = 0; i < xLength; i++) {
X[i].addEventListener('click', startAction, false);
}
});
.addBGoverlay {
background-color: gray;
}
.bG {
background-color: white;
}
<a class="dash-menu mega-menu-link " role="button" href="#"><span class="mega-indicator">navButtn</span></a>
Just change
var bg = document.getElementsByTagName('body')[0];
This will fix the error.
It must resolve your's problem.
you no need to get an element for the body. Document have that one. So
just concatenate the new class.
function startAction() {
alert('This a popUp');
document.body.className += "addBGoverlay";
}

Javascript loading speed issue as variable increases

I am having an issue with page loading time. Currently right now I am running UBUNTU in Oracle Vm Virtual Box. I am using mozilla firefox as my browser and I am working on an etchasketch project from "The odin project".
My problem is the page loading time. The code takes a prompt at the start and generates a grid for the etch a sketch based on that prompt. I have not given it the minimum and maximum values (16 and 64) respectively, however any number when prompted at the beginning that is beyond 35 doesn't load or takes ages to load.
How do I speed up the process time? / why is it moving so slow? / how can I avoid this ? / is there a fix that I am over looking that can make this work a lot faster? / feel free to tackle any and all of those questions!
This is my HTML CODE:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8"/>
<title>
</title>
</head>
<body>
<div class="etchhead">
<p> Choose your grid size </p>
<input type = "text"></input>
<button id="startOver"> Clear Grid </button>
<p> Change color </p>
</div>
<div id="grid">
</div>
<script src="eas.js"></script>
</body>
</html>
And this is my CSS code:
p {
color: blue;
display: inline;
}
#grid {
display: grid;
width: 800px;
max-width: 800px;
height: 800px;
max-height: 800px;
line-height: 0;
}
.gridBox {
border: 1px solid black;
background-color: lightgrey
}
And this is my JAVASCRIPT code:
gridStart();
function gridStart(){
var boxes = 0
var selectBody = document.querySelector("#grid");
var addBox = document.createElement("div");
var boxCountStart = prompt("enter a number between 16 and 64");
var boxDimensions = (boxCountStart * boxCountStart);
function rowsAndColumns() {
var selectBody = document.querySelector("#grid");
var gridTemplateColumns = 'repeat('+boxCountStart+', 1fr)';
selectBody.style.gridTemplateColumns= gridTemplateColumns;
selectBody.style.gridTemplateRows= gridTemplateColumns;
};
function hoverColor(){
var divSelector = selectBody.querySelectorAll("div");
divSelector.forEach((div) => {
div.addEventListener("mouseover", (event) => {
event.target.style.backgroundColor = "grey";
});
});
};
rowsAndColumns();
for (boxes = 0; boxes < boxDimensions ; boxes++) {
var selectBody = document.querySelector("#grid");
var addBox = document.createElement("div");
addBox.classList.add("gridBox");
addBox.textContent = (" ");
selectBody.appendChild(addBox);
hoverColor();
};
};
There are two components to your issue. One is that you are repeatedly modifying the DOM in a loop. You can fix it by appending all your boxes to a DocumentFragment and then adding that to the DOM after your loop finishes. You are also calling hoverColor(); inside your loop which results in adding tons of event listeners that all do the same thing (since inside hoverColor you are adding a listener to every single div). You can fix both those issues like this:
var fragment = document.createDocumentFragment( );
for (var i = 0; i < boxDimensions ; i++) {
var addBox = document.createElement("div");
addBox.classList.add("gridBox");
addBox.textContent = (" ");
fragment.appendChild(addBox);
}
document.querySelector("#grid").appendChild( fragment );
hoverColor();
Here is a JSFiddle with your original code, and here is one with the modification.
You could also benefit from only having one event listener total. You don't need to loop and add an event listener to every div. Just add one to #grid and use event.target (like you already do, to find the div that the event originated from). Something like this:
function hoverColor(){
document.querySelector("#grid").addEventListener( 'mouseover', function ( event ) {
event.target.style.backgroundColor = "grey";
} );
}

How do I make a JavaScript created list item clickable?

I've been going through all the related questions but none of the solutions have been working for me. I am extremely new to JavaScript and I'm confused as to how to make a list that I created with JavaScript have clickable items. The most recent attempt included attempting to make an alert pop up on click but instead it just pops up the second the page loads. Please help! Here is my current code:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="css/m-buttons.css">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
div.links{
margin: auto;
border: 3px solid #003366;
text-align: left;
max-width: 700px;
}
p{
font-size: 40px;
text-align: center;
}
li{
font-size: 1w;
}
body{
font-family: verdana;
}
</style>
</head>
<body>
<div class = "links">
<ul id="blah"></ul>
<script>
var testArray = ["One","Two","Three","Four","Five","Six","Seven"];
function makeLongArray(array){
for(var i = 0; i < 1000; i++){
array.push(i);
}
}
makeLongArray(testArray);
function makeUL(array) {
// Create the list element:
var list = document.createElement("UL");
list.setAttribute("id", "blah");
for(var i = 0; i < array.length; i++) {
// Create the list item:
var item = document.createElement("LI");
// Set its contents:
item.appendChild(document.createTextNode(array[i]));
// Add it to the list:
list.appendChild(item);
list.onclick = alert("Help."); //this is the code causing the issue.
}
// Finally, return the constructed list:
return list;
}
// Add the contents of options[0] to #foo:
document.getElementById("blah").appendChild(makeUL(testArray));
</script>
</div>
</body>
</html>
Your existing code will execute alert('Help.') every time you execute this line of code list.onclick = alert("Help.");
What you need to do is assign a function to onclick. This function then get executed when onclick is executed. As follows:
item.onclick = function() {console.log('hello world');};
Now each list item's onclick event has a function assigned to it that outputs hello world to the console everytime the list item is clicked.
You need to assign a function to the onclick event:
list.onclick = function(){ alert("Help."); }
Here is my solution:
function toggleDone(event) {
var ev = event.target;
ev.classList.toggle("done");
}
ul.addEventListener("click", toggleDone);

How to know when a particular button is clicked in Javascript?

I'm making a function that displays a modal, and the modal has two buttons. I want this function to wait until one of the two buttons has been clicked, and return a value that corresponds to which button is clicked.
Here's a sample code that I came up with:
function myFunc()
{
var val=0;
buttonA = document.getElementById('buttonA');
buttonB = document.getElementById('buttonB');
buttonA.onclick = function(){
//do something
val = 1;
}
buttonB.onclick = function(){
//do something
val = 2;
}
while(val == 0);
return val;
}
The problem in this code is that the page becomes unresponsive because of the infinite loop, hence it isn't possible to change the value of val once initialised.
To be more precise, I want the main thread (on which myFunc is being implemented) to sleep until one of the other two threads (each of buttonA and buttonB) is clicked.
Is there some other work-around for this ? Please answer in Javascript only (no jQuery). Thanks.
Try something more like this:
function myFunc()
{
buttonA = document.getElementById('buttonA');
buttonB = document.getElementById('buttonB');
buttonA.onclick = function(){
//do something
differentFunc(1)
}
buttonB.onclick = function(){
//do something
differentFunc(2)
}
}
This is a different way to make the function more versatile (edited per your comment):
function myFunc(callback)
{
buttonA = document.getElementById('buttonA');
buttonB = document.getElementById('buttonB');
buttonA.onclick = function(){
//do something
callback(1)
}
buttonB.onclick = function(){
//do something
callback(2)
}
}
and call it like
myFunc(function(result) {
// do stuff with result
}
Javascript is naturally single-threaded. Any code that waits infinitely like that will cause a hangup and disallow input. There are ways to write async functions, namely using Promises like I did for a minute there, but it's generally easier to make your code work synchronously.
If I understand the OP's purpose is to create a modal with 2 choices like a confirm()? But for some reason confirm() isn't suitable? So a value on each button and it waits for user interaction? Unless I'm missing something fairly important, I have made a dynamically generated modal (no manual markup) that has 2 buttons. The purpose and result elude me so I left it with one event listener and a function with a simple ternary condition to which the alerts can be replaced by appropriate statements or expression at OP's discretion.
SNIPPET
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
.modal {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100vw;
background:transparent;
}
.ui {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: table-cell;
border: 3px ridge grey;
border-radius: 6px;
}
button {
font-size: 24px;
}
</style>
</head>
<body>
<script>
var frag = document.createDocumentFragment();
var modal = document.createElement('div');
var ui = document.createElement('div');
var on = document.createElement('button');
var off = document.createElement('button');
modal.className = 'modal';
ui.className = 'ui';
on.id = 'on';
on.textContent = 'On';
off.id = 'off';
off.textContent = 'Off';
frag.appendChild(modal);
modal.appendChild(ui);
ui.appendChild(on);
ui.appendChild(off);
ui.addEventListener('click', status, false);
function status(e) {
var tgt = e.target.id;
tgt === 'on' ? alert('ON!') : alert('OFF!');
}
document.body.appendChild(frag);
</script>
</body>
</html>

Categories