I have a HTML/JS code as shown below in which on click of Execute button, I want to display:
[{"detail":"Hello World"},{"detail":"Great News"}]
Currently, on clicking Execute button I am getting the following:
[{"detail":""},{"detail":""}]
I am wondering what changes I need to make in the JS code below so that on click of a Execute button, I am able to display:
[{"detail":"Hello World"},{"detail":"Great News"}]
HTML:
<input type="submit" onClick="runCode()" value="Execute" >
<div id="console-log">
</div>
Javascript:
$(document).ready(function() {
})
function runCode(){
var td=new Todo()
td.addTask("Hello World")
td.addTask("Great News")
td.printList()
}
class Todo{
constructor(name) {
this.todolist = [];
this.task={
'detail':''
}
}
addToList(newobj)
{
this.todolist.push(newobj)
}
addTask(taskDetail){
this.task.detail=taskDetail
this.todolist.push(this.task)
this.task.detail='' //clear data for next step
}
printList()
{
var consoleLine = "<p class=\"console-line\"></p>";
var text= JSON.stringify(this.todolist)
$("#console-log").append($(consoleLine).html(text));
//alert(this.todolist)
}
}
Push an object created just from the argument into the todolist property:
addTask(detail) {
this.todolist.push({ detail });
}
The this.task property only makes things more confusing, I'd recommend avoiding it.
function runCode() {
var td = new Todo()
td.addTask("Hello World")
td.addTask("Great News")
td.printList()
}
class Todo {
constructor(name) {
this.todolist = [];
}
addTask(detail) {
this.todolist.push({ detail });
}
printList() {
var consoleLine = "<p class=\"console-line\"></p>";
var text = JSON.stringify(this.todolist)
$("#console-log").append($(consoleLine).html(text))
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="submit" onClick="runCode()" value="Execute">
<div id="console-log">
</div>
It would also be trivial to remove the dependency on the big jQuery library if you wanted, it's not accomplishing anything useful. Also, it'd be good practice to use addEventListener instead of an inline handler:
document.querySelector('input').addEventListener('click', () => {
var td = new Todo()
td.addTask("Hello World")
td.addTask("Great News")
td.printList()
});
class Todo {
constructor(name) {
this.todolist = [];
}
addTask(detail) {
this.todolist.push({ detail });
}
printList() {
document.querySelector('code').appendChild(document.createElement('p'))
.textContent = JSON.stringify(this.todolist);
}
}
<input type="submit" value="Execute">
<code>
</code>
Related
Is there a way to simplify the below code by using an array? For example, when button 1 (with the index of 0) in the HTML is clicked, could that be used to get a value at index 0 in another array?
function f1() {
document.getElementById("dis").innerHTML = "JoeMae";
}
function f2() {
document.getElementById("dis").innerHTML = "TanakaMae";
}
function f3() {
document.getElementById("dis").innerHTML = "James";
}
function f4() {
document.getElementById("dis").innerHTML = "Deus";
}
<button onclick="f1()">no.1</button>
<button onclick="f2()">no.2</button>
<button onclick="f3()">no.3</button>
<button onclick="f4()">no.4</button>
<p id="dis"></p>
You can simplify without using array:
<button onclick="f('JoeMae')">no.1</button>
<button onclick="f('TanakaMae')">no.2</button>
<button onclick="f('James')">no.3</button>
<button onclick="f('Deus')">no.4</button>
<p id="dis"></p>
function f(str) {
document.getElementById("dis").innerHTML = str;
}
Use another array such that the nth index of that array corresponds to the nth button:
const texts = [
"JoeMae",
"TanakaMae",
"James",
"Deus"
];
const dis = document.getElementById("dis");
document.querySelectorAll('button').forEach((button, i) => {
button.addEventListener('click', () => {
dis.textContent = texts[i];
});
});
<button>no.1</button>
<button>no.2</button>
<button>no.3</button>
<button>no.4</button>
<p id="dis"></p>
Note that unless you're deliberately inserting HTML markup, you should probably use textContent, not innerHTML. (textContent is faster and safer)
Here's an approach that's vanilla JS. I used the dataset API to connect each button to its data, then a single handler to retrieve and display this data.
"use strict";
function byId(id){return document.getElementById(id)}
function newEl(tag){return document.createElement(tag)}
window.addEventListener('load', onLoaded, false);
function onLoaded(evt)
{
var responseArray = ['JoeMae', 'TanakaMae', 'James', 'Deus'];
responseArray.forEach( function(arrElem, elemIndex, arr)
{
var btn = newEl('button');
btn.textContent = `no.${elemIndex+1}`;
btn.dataset.response = arrElem;
btn.addEventListener('click', onClick, false);
document.body.appendChild(btn);
}
);
function onClick(evt)
{
let text = this.dataset.response;
byId('dis').textContent = text;
}
}
<p id='dis'></p>
Here's a slightly cleaner and more flexible example how to implement this type of functionality.
If you are having a lot of rendering functionality like this, I would recommend you to use a library/framework for it, though.
const buttonDefinitions = [
{title: 'no.1', name: 'Monica'},
{title: 'no.2', name: 'Erica'},
{title: 'no.3', name: 'Rita'},
{title: 'no.4', name: 'Tina'}
];
const buttonContainer = document.getElementById('buttonContainer');
const resultContainer = document.getElementById('resultContainer');
for (const buttonDefinition of buttonDefinitions) {
const button = document.createElement('button');
button.innerHTML = buttonDefinition.title;
button.onclick = () => {
resultContainer.innerHTML = buttonDefinition.name;
};
buttonContainer.appendChild(button);
}
<div id="buttonContainer"></div>
<div id="resultContainer"></div>
You can pass the element to the function and access the element data-attributes
In the below example I am passing data-name
function f(element) {
document.getElementById("dis").innerHTML = element.dataset["name"];
}
<button data-name="JoeMae" onclick="f(this)">no.1</button>
<button data-name="TanakaMae" onclick="f(this)">no.2</button>
<button data-name="James" onclick="f(this)">no.3</button>
<button data-name="Deus" onclick="f(this)">no.4</button>
<p id="dis"></p>
I'm building my little lib js.
my intent is to have both possibilities in this way:
//this:
core.find(".myclass").myAction (actor);
var target = core.target (".myclassname");
core.myAction (target, actor);
//or:
core.find(".myclass").myAction (actor);
var target = core.find(".myclassname");
core.myAction (target, actor);
//so, return the finded for core and gearcore, but
//I can not and I do not think it's feasible (is it?)
//this isn't a good solution... thanks.
//var target = core.find(".myclassname");
//target .myAction (target, actor);
anyway... the first is chained, the second part from the first class and generates the action through a parameter.
yes, I already know that I can create a copy of the functions, but it's disgusting ... and copy the target how can I solve it?
here it's about joining the two "find" or putting the two return or joining the two return or something else or maybe something similar.
for convenience: lib in jsfiddle else...
LIB:
note 1:the two eval functions are just a demo to get an answer. the complete lib contains more and I need to assign the target in both ways
class coregears {
constructor(gear) {
this.gear = gear;
}
actor(target, fname) {
alert("inside actor");
let t_, f_;
(1 == arguments.length) ? (t_ = this.gear, f_ = target) : (t_ = target, f_ = fname);
t_.forEach((looped) => { eval(f_)(looped); return this.gear});
}
}
class Core {
// return for core.function(target,actor);
target(subject)
{
let name;
var finded;
if (subject.startsWith(".")) {
name = subject.split(".")[1];
finded = [...document.getElementsByClassName(name)];
}
if (subject.match(/\B\#\w\w+\b/g)) {
name = subject.replace(/#(\S*)/g, 'ID_$1').split("ID_")[1];
finded = [...document.querySelectorAll("#" + name)];
}
if (subject.startsWith("[")) {
finded = [...document.querySelectorAll(subject)];
}
return finded;
}
// return for core.find(target).function(actor);
find(subject){
let name;
if (subject.startsWith(".")) {
name = subject.split(".")[1];
find = [...document.getElementsByClassName(name)];
}
if (subject.match(/\B\#\w\w+\b/g)) {
name = subject.replace(/#(\S*)/g, 'ID_$1').split("ID_")[1];
find = [...document.querySelectorAll("#" + name)];
}
if (subject.startsWith("[")) {
find = [...document.querySelectorAll(subject)];
}
return new coregears(find);
}
}
const core = new Core();
SCRIPT:
//chain
core.find(".test_Y").actor(myactor_1);
function myactor_1(looped) {
alert("actor_1");
looped.style = "font-weight: bold; color: magenta;";
};
//direct
var mytarget = core.target(".test_X");
core.actor(mytarget,myactor_2);
function myactor_2(looped) {
alert("actor_2");
looped.style = "font-weight: bold; color: green;";
};
HTML:
<div class="test_X">SIMPLE TEST CLASS</div>
<div class="test_X">SIMPLE TEST CLASS</div>
<div class="test_X">SIMPLE TEST CLASS</div>
<div class="test_Y">SIMPLE TEST CLASS</div>
<div class="test_Y">SIMPLE TEST CLASS</div>
<div class="test_Y">SIMPLE TEST CLASS</div>
Idea?
update: I replaced the eval with f_.call(this,looped); thank you #Shilly.
Using Meteor framework version 1.2.1
I have a form which adds data to Mongo collection. However I find that the javascript code executes without errors (and all the debug console.log messages appear as i expect) but still the collection doesn't have the data which i just inserted. The issue is that this happens kind of randomly. So sometimes the insertion is working and at other times the insertion doesn't work. Similar issue with the upsert command. my html and js code is pasted below (Note i haven't removed autopublish and insecure packages). Unable to figure what the issue in my code is and need help in this matter
JS Code
ProjectList = new Mongo.Collection("projectList");
ListItem = new Mongo.Collection("listItem");
if (Meteor.isClient) {
Template.create.events({
'submit .add_chapter': function (event) {
var addtoWhat;
var chapName = event.target.chapName.value;
if (event.target.addToWhat.value) {
if (event.target.addToWhat.value.length > 0) {
addtoWhat = event.target.addToWhat.value;
} else {
}
} else {
}
if (addtoWhat) {
var addToWhatItem = ListItem.findOne({name:addtoWhat});
var item = {
name : chapName,
list : [],
}
var id = ListItem.insert(item);
if (id) {
addToWhatItem.list.push(id);
if (!ListItem.upsert({_id:addToWhatItem._id}, addToWhatItem)) {
alert("Unable to upsert");
}
} else {
alert("Unable to insert");
}
} else {
var projList;
if (!ProjectList.findOne({projectId:"123"})) {
projList = {
projectId : "123",
list : [],
};
var topid = ProjectList.insert(projList);
if (topid) {
console.log ("Top Insert succesful with id " + topid);
} else {
console.log ("Error Top Insert unsuccesful with id ");
}
}
projList = ProjectList.findOne({projectId:"123"});
var item = {
name : chapName,
list : [],
}
var id = ListItem.insert(item);
projList.list.push(id);
if(!ProjectList.upsert({_id:projList._id}, projList)) {
console.log("Upsert failed");
} else {
console.log("Upsert successful");
}
}
},
'submit .gen_tree' : function(event) {
getElements();
}
});
function getElements() {
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
HTML Code
<head>
<title>test_hierarchy2</title>
</head>
<body>
<h1>Welcome to Meteor!</h1>
{{> create}}
</body>
<template name="create">
<form class="add_chapter" method="post">
<label>addToWhat</label>
<input type="text" name="addToWhat">
<label>chapName</label>
<input type="text" name="chapName">
<button type="submit">Add</button>
</form>
<form class="gen_tree" method="post">
<button type="submit">generate</button>
</form>
</template>
Try this
ProjectList.update({_id:projList._id}, projList, {upsert:true}, function(error,doc){
if(error){
console.log(error);
}
else{
console.log(doc);
}
})
I have the following html:
<div ng-show=showMarketingNav>
...
</div>
<div ng-show=showProductsNav>
...
</div>
<div ng-show=showSettingsNav>
...
</div>
What I want to do is to easily be able to hide all but one of the divs from another controller. I thought I could be clever and do the following:
var subNavMenuDisplays = {
Marketing: $scope.showMarketingNav,
Products: $scope.showProductsNav,
Settings: $scope.showSettingsNav
}
$rootScope.hideContextMenu = function () {
for (var category in subNavMenuDisplays) {
subNavMenuDisplays[category] = false;
}
}
$rootScope.setContextMenu = function (name) {
$rootScope.hideContextMenu();
subNavMenuDisplays[name] = true;
}
but this obviously does not work as $scope.showMarketingNav etc. will be passed as value, not reference.
The following works, but is not exactly nice to work with:
$rootScope.hideContextMenu = function () {
$scope.showMarketingNav = false;
$scope.showProductsNav = false;
$scope.showSettingsNav = false;
}
$rootScope.setContextMenu = function (name) {
$rootScope.hideContextMenu();
if (name == "Marketing") {
$scope.showMarketingNav = true;
}
if (name == "Products") {
$scope.showProductsNav = true;
}
if (name == "Settings") {
$scope.showSettingsNav = true;
}
}
Is there a way to grab $scope.showMarketingNav by reference, or another clever way around this?
I'd prefer not using eval to concatenate variable names.
You can place an object on the $scope and then toggle it dynamically:
$scope.show = {};
$rootScope.setContextMenu = function (name) {
$scope.show = {};
$scope.show[name] = true;
}
And the Html:
<div ng-show="show.Marketing">
...
</div>
<div ng-show="show.Products">
...
</div>
<div ng-show="show.Settings">
...
</div>
Here's a plunker demonstrating the change.
You can assign simple updater functions in that object:
Marketing: function(val) { $scope.showMarketingNav = val },
Products: function(val) { $scope.showProductsNav = val},
Settings: function(val) { $scope.showSettingsNav = val}
Then call it:
subNavMenuDisplays[name](true);
I have created an object where i need to assign some variables(parameters) and when the object is called, the variables(parameters) change. Here is my code:
var Modal = {
init: function () {
contact1: "";
contact2: "";
aboutus1: "";
aboutus2: "";
privacy1: "";
privacy2: "";
terms1: "";
terms2: "";
$(".modaltrigger").removeAttr("target");
$(".modaltrigger").click(function () {
if ($(this).is("#contact")) {
$('#primary_url').attr('href', contact1);
$('#secondary_url').attr('href', contact2);
} else if ($(this).is("#aboutus")) {
$('#primary_url').attr('href', aboutus1);
$('#secondary_url').attr('href', aboutus2);
} else if ($(this).is("#termsconditions")) {
$('#primary_url').attr('href', terms1);
$('#secondary_url').attr('href', terms2);
} else if ($(this).is("#privacy")) {
$('#primary_url').attr('href', privacy1);
$('#secondary_url').attr('href', privacy2);
}
});
}
};
I am trying to initialize the object above, and it does not work:
Modal.init(
contact1: "http:www.test1.com";
contact2: "http:www.test2.com";
aboutus1: "http:www.test3.com";
aboutus2: "http:www.test4.com";
privacy1: "http:www.test5.com";
privacy2: "http:www.test6.com";
terms1: "http:www.test7.com";
terms2: "http:www.test8.com"
);
it is Done like this way,
i Guess this is what you want to do.
var Modal = {
init: function (args) {
//then access your values like this
contact1= args.contact1;
contact2 = args.contact2;
..........
.........
.........
}
}
And to initiate this method you have write as
Modal.init({
contact1:"contact str",
contact2:"contact str",
.....
.....
lastitem : "last str"
});