Trying to generate a button-based interface in javascript - javascript

I am trying to build an interface with javascript. The interface is a grid of buttons. Each row is a different musical instrument and on each column you have a rhythm pattern you can trigger.
When the user click on a button, I want it to change its class so the background-color changes, telling to user it's been activated.
The problem is, my script is always targeting the last button of a row. When I try to force it to target a specific button (which is NOT the last button), it says the button in "undefined".
pattern1 = ["Clave 1",[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0],"description"];
pattern2 = ["Clave 2",[1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,0,1],"description"];
pattern3 = ["Clave 3",[1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1],"description"];
pattern4 = ["Clave 4",[1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0],"description"];
pattern5 = ["Clave 5",[1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1],"description"];
pattern6 = ["Clave 6",[1,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0],"description"];
pattern7 = ["Clave 7",[1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1],"description"];
pattern8 = ["Clave 8",[1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0],"description"];
var pattern_collection = [pattern1, pattern2, pattern3, pattern4, pattern5, pattern7, pattern8];
function generate_buttons(instrument_id) {
for (var key in pattern_collection)
{
//creating an array of button for each instrument
var button = new Array();
//creating the button label
var button_text;
button_text = document.createTextNode(pattern_collection[key][0]);
//creating the button in the DOM
button[key] = document.createElement('div');
//by default, the first pattern is shown as playing
if (pattern_collection[key]==pattern1)
button[key].className = "isplaying_pattern_button";
else
button[key].className = "notplaying_pattern_button";
button[key].onclick = function() {
//picking the currently playing button to change its class to not playing
var playing_button = document.querySelector("#"+instrument_id+" .isplaying_pattern_button");
playing_button.className = "notplaying_pattern_button";
//this is where the problem occurs: the script is always targeting the last button of the row
button[key].className = "isplaying_pattern_button";
};
button[key].appendChild(button_text);
var instrument_patterns = document.getElementById(instrument_id);
instrument_patterns.appendChild(button[key]);
}
}

Related

Javascript addEventListener not working properly

So i'm having trouble with the event so, normally i try to create an event if we have more than 1 image in the array so i can mouseenter and display another one but currently i don't know why but when we mouseenter the preview (image) it giving the latest result from the array while we still inside the loop ?
var product_type = "";
for(let i = 0; i < this.products_list.length; i++){
var row = this.products_list[i], self = this;
if(row.product_type != product_type){
product_type = row.product_type;
var sub_title = document.createElement("h2"),
separator = document.createElement("hr"),
display_list = document.createElement("ul");
sub_title.id = product_type;
sub_title.innerHTML = localeString.get(product_type);
display_list.id = product_type+"-list";
this.catalog.appendChild(sub_title);
this.catalog.appendChild(separator);
this.catalog.appendChild(display_list);
}
var product = document.createElement("li"),
preview = document.createElement("img"),
container = document.createElement("div");
var array_images = row.product_images.split(",");
preview.src = this.assets+product_type+"/"+array_images[0]+".jpg";
preview.alt = product_type+"#"+row.product_id;
container.appendChild(preview);
product.appendChild(container);
preview.addEventListener("mouseenter", event => {
console.log(array_images);
//here, giving the latest element from the array and not the current selected.
});
display_list.appendChild(product);
}
If your are trying to opt for mouseover event then you should use mouseover in the place of click event. Currently its not working because the event which you called is a click event.

How can i target appended items one by one in javascript?

I created a simple new tab page similar to web browsers, but when I create a new tab and press the x icon to triger closetab() it closes all the tabs and does not delete them in order one by one. How do i make each of appended items unique?
JS:
function addTab() {
var img = document.createElement("img");
img.src = "resources/img/delete-icon.svg";
img.className = 'deleteicon';
img.id = "deletetab";
img.onclick = closeTab;
var ulLocation = document.getElementsByClassName('abc')[0];
var whereTab = document.getElementById('listid');
var addTab = document.createElement('li');
addTab.className = 'first-tab';
addTab.id = "listid";
addTab.className = 'active';
addTab.innerHTML = "mozilla-firefox/newtab";
addTab.appendChild(img2);
ulLocation.appendChild(addTab);
addTab.appendChild(img);
}
function closeTab() {
var whereTab = document.getElementById('listid');
if (whereTab.style.display == 'block') {
whereTab.style.display = 'none';
} else {
whereTab.style.display = "none";
}
}
You have at least 2 options. One is to target the active tab and close it when the X is clicked. This is assuming you only have one active tab at a time (denoted by an active class for example).
function closeTab(event) {
document.querySelector('li.tab.active').remove();
}
Another option is to reference the tab relative to the close icon, which you can reference in the event argument of your click listener. Since you're adding these dynamically, you can just remove them with the delete click rather than hide. Something like:
function closeTab(event) {
event.target.closest('li.tab').remove();
}
In these examples, you have set a className for your tab containers to be tab

Indesign 2020 ScriptUI add text frame

I have a problem with a script for Indesign 2020.
I am not a programmer and don't know javascript (I just created some simple script).
I want to create a simple panel with a button that add a textframe, but doesn't seems to work.
Here's the code
var document = app.activeDocument;
document.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.MILLIMETERS;
document.viewPreferences.verticalMeasurementUnits = MeasurementUnits.MILLIMETERS;
app.viewPreferences.rulerOrigin = RulerOrigin.SPREAD_ORIGIN;
app.activeDocument.viewPreferences.rulerOrigin = RulerOrigin.SPREAD_ORIGIN;
app.activeDocument.zeroPoint = [0,0];
var Labelpanel = new Window("dialog");
Labelpanel.text = "Printer";
Labelpanel.orientation = "column";
Labelpanel.alignChildren = ["center","top"];
Labelpanel.spacing = 10;
Labelpanel.margins = 16;
var Button1 = Labelpanel.add("button", undefined, undefined, {name: "Button 1"});
Button1.text = "Magenta 1";
Button1.onClick = function() {
var Label = document.pages[0].textFrames.add();
Label.properties = {
geometricBounds : [ 25,284.5,15,226.5 ],
contents : "1234_Mag1"
}
Label.paragraphs[0].appliedFont = app.fonts.item("Arial");
Label.paragraphs[0].pointSize = "30";
Label.paragraphs[0].justification = Justification.RIGHT_ALIGN;
Labelpanel.close();
}
Labelpanel.show();
The code in the button normally works, but in ScriptUI it does nothing.
Can someone tell me what am I doing wrong?
In your case the script will work (I'm not sure about your goal, though) if you add this line:
#targetengine session
at the start of the code.
And change "dialog" with "palette" here:
var Labelpanel = new Window("palette");
The problem is a dialog window can't change a document until the dialog will be closed.
Not like a palette that has access to documents always.
Your script can be rewritten in order to use a dialog window instead of palette. But it will need to change more than just two lines.
Update
Here is the example how it can be done with a dialog window:
// set the dialog window
var labelDialog = new Window("dialog");
labelDialog.text = "Printer";
labelDialog.orientation = "column";
labelDialog.alignChildren = ["center","top"];
labelDialog.spacing = 10;
labelDialog.margins = 16;
// set a variable that we will convey to the main function
var contents = '';
// a couple buttons
var button1 = labelDialog.add("button", undefined, undefined, {name: "Button 1"});
button1.text = "Magenta 1";
var button2 = labelDialog.add("button", undefined, undefined, {name: "Button 2"});
button2.text = "Magenta 2";
// if click --> change the variable an close the dialog
button1.onClick = function() {contents = '1234_Mag1'; labelDialog.close()};
button2.onClick = function() {contents = '5678_Mag2'; labelDialog.close()};
labelDialog.show(); // show the dialog
// if the variable is not empty --> run the main function
if (contents != '') main(contents);
// the main function, get the variable and does the work
function main(contents) {
app.viewPreferences.rulerOrigin = RulerOrigin.SPREAD_ORIGIN;
app.activeDocument.viewPreferences.rulerOrigin = RulerOrigin.SPREAD_ORIGIN;
app.activeDocument.zeroPoint = [0,0];
var document = app.activeDocument;
document.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.MILLIMETERS;
document.viewPreferences.verticalMeasurementUnits = MeasurementUnits.MILLIMETERS;
var label = document.pages[0].textFrames.add();
label.properties = {
geometricBounds: [ 25,284.5,15,226.5 ],
contents: contents // <-- our variable goes here
}
label.paragraphs[0].appliedFont = app.fonts.item("Arial");
label.paragraphs[0].pointSize = "30";
label.paragraphs[0].justification = Justification.RIGHT_ALIGN;
}
I've made two buttons. I suspect it would be your next question: "How to add more buttons?"
The main point: A dialog window should be closed before you try to change a document. A palette should not. This 'subtle difference' changes the algorithm significantly.

Rendering Info Cards and modal box with forLoop only outs the last result in one of the fields

I am practising vainilla JS and DOM manipulation. I am rendering a group of cards populated with data from an Object (that I fetch from an API, but this happens also if i do it in local).
I get to render the cards,all good, and create a button in each of them, that triggers a Modal box made with Bootstrap, with some additional information about that item.
The problem I have is that when I click on the button, the modal box only displays the information from the last element of the Object.
The function i wrote is as follows :
function createCards(data) {
let cardContainer = document.getElementById('cardContainer');
let modalTitle = document.getElementById('modalTitle');
let modalBody= document.getElementById('modalBody');
for (let i = 0; i < data.length; i++) {
let divCard = document.createElement('div');
divCard.setAttribute('class', 'card');
let imgFish = document.createElement('img');
imgFish.setAttribute('class', 'card-img-top');
let imgUrl = data[i]['Species Illustration Photo'].src
// console.log(imgUrl)
imgFish.setAttribute('src', imgUrl);
let divCardBody = document.createElement('div');
divCardBody.setAttribute('class', 'card-body');
let hCardTitle = document.createElement('h5')
hCardTitle.innerHTML = data[i]['Species Name'];
let pCardText = document.createElement('p');
pCardText.setAttribute('class', 'card-text');
pCardText.innerHTML = 'Kcal = ' + data[i].Calories
let aInfoButton = document.createElement('a');
aInfoButton.setAttribute('class', 'btn btn-primary');
aInfoButton.setAttribute('href', '#');
aInfoButton.setAttribute('data-toggle', 'modal');
aInfoButton.setAttribute('data-target', '#myModal');
aInfoButton.innerHTML = 'Nutrional Info'
cardContainer.appendChild(divCard);
divCard.appendChild(imgFish);
divCard.appendChild(divCardBody);
divCardBody.appendChild(hCardTitle);
divCardBody.appendChild(pCardText);
divCardBody.appendChild(aInfoButton);
//fill in Modal box
aInfoButton.onclick = function () {
createModal(data);
}
}
console.log("createCards() run")
}
and then, the function to populate the modal box :
function createModal(data) {
let modalTitle = document.getElementById('modalTitle');
let modalBody= document.getElementById('modalBody');
for (let i = 0; i < data.length; i++) {
modalTitle.innerHTML = data[i]['Species Name'];
modalBody.innerHTML = data[i]['Cholesterol'];
}
}
I tried also wrapping the creation of those two innerHTML from the modal box inside a different function, thinking it was a problem of time needed to render each item, but it seems that the problem is different, and I can't see which one.
It looks like, at the bottom of your for-loop, you are overwriting the innerHTML every time.
modalTitle.innerHTML = data[i]['Species Name'];
modalBody.innerHTML = data[i]['Cholesterol'];
So when you exit the for loop, what ever iteration of data is last is the one that will be in the modal.
2 ways to go about fixing:
1.) create a modal specific to each card.
2.) add an eventListener to the button that will populate the correct info onclick

Javascript/Jquery toggle id with multiple variable

this is my first question, so apologies if not written clearly.
I want to dynamically toggle a comment form after reply button is pressed. There are multiple comments (in below example three) to which a form (with different id) can be rendered separately.
I am able to do this with static id for form but not with dynamically defined id...
I have tried this static approach and this works fine.
var functs_t = {};
functs_t['fun_27'] = $('#reply_comment_id_27').click(function() {$('#form_comment_id_27').toggle('slow');});
functs_t['fun_23'] = $('#reply_comment_id_23').click(function() {$('#form_comment_id_23').toggle('slow');});
functs_t['fun_21'] = $('#reply_comment_id_21').click(function() {$('#form_comment_id_21').toggle('slow');});
However, I am having struggling with a dynamic approach.
var i;
var functs = {};
for (i=0; i<comment_qs_id_list.length; i++) {
var comment_id = comment_qs_id_list[i].toString();
var reply_comment_id = 'reply_comment_id_'+ comment_id;
var form_comment_id = $('#'+reply_comment_id).attr('name');
// works >>> toggles comment 27
functs['func_reply_comment_'+comment_qs_id_list[i]] = $('#reply_comment_id_'+comment_qs_id_list[i]).click(function() {$('#'+'form_comment_id_27').toggle('slow');});
// does not work
//functs['func_reply_comment_'+comment_qs_id_list[i]] = $('#reply_comment_id_'+comment_qs_id_list[i]).click(function() {$('#'+form_comment_id).toggle('slow');});
// works >> toggles everything (but what I want is to hide initially and only toggle after clicking reply button)
//$('#'+form_comment_id).toggle('slow');
};
Thanks so much!

Categories

Resources