Calling a function onclick in Svelte - javascript

I began using svelte for a recent project, and although I like the workflow of the framework so far, I've yet to get a single function to work successfully.
Currently, I'm trying to change the innerHTML of a series of objects using functions.
Below is my code:
<head>
<script>
export let question1() {
document.getElementByClass(questionBox).innerHTML = "True or False?";
document.getElementById(ans_1).innerHTML = "True";
document.getElementById(ans_2).innerHTML = "False";}
</script>
</head>
<body>
<div class="container">
<button on:click={question1} class="startButton">Start Game</button>
<div class="box"><span id="questionBox">...</span></div>
</div>
<div class="option-container">
<button class="option" id="ans_1">option1</button>
<button class="option" id="ans_2">option2</button>
</div>
</body>
There is an error marked beneath my function when I call it on:click in the button, and that error reads as follows:
'question1' is not defined. Consider adding a <script> block with 'export let question1' to declare a propsvelte(missing-declaration)
I am quite new to svelte and it's entirely possible I misunderstood something structurally within my code, but I've checked all over and can't seem to find anything that quite addresses my problem.
Any help would be quite appreciated. Perhaps I just need some new eyes on this.
Thank you.

Here's the list of things you might have gotten wrong.
Function declaration
This is valid:
function question1() {
//dosomething
}
This is valid too (arrow function):
let question1 = () => {
//dosomething
}
But this is not a correct way:
let question1() {
//dosomething
}
getElementByClass is not a correct method. You probably meant getElementsByClassName.
document.getElementByClassName("questionBox").innerHTML = "something"
Note that if you have more than one element with that class name, only the first item will be affected.
Easiest way to get a single element is to use:
//by class name
document.querySelector(".classname")
//by id
document.querySelector("#id")
//by element type
document.querySelector("div")
You dont need to add <head> tag in your code. Each svelte file can have a <script> and <style> element in the component at top level.
You are trying to change text in elements in a Vanilla JS way. You should probably populate the DOM using data so that you are taking advantage of Svelte's amazing reactivity. Look at this REPL to see a replication of what you are trying to do in a more Svelty way. Basically, use data to dynamically render the DOM elements. That way, you will never directly manipulate the DOM Elements. Just change your data and Svelte takes care of changing the DOM.
https://svelte.dev/repl/8316ae63d83b443aaef5aa7b29c36dc1?version=3.53.1
Use betternames for your functions. question1 as a function name is not descriptive of what you are doing inside.
If you still want to modify the DOM elements directly, you can bind them to variables like so and change text like so:
https://svelte.dev/tutorial/bind-this

Related

Add complexe Javascript array elements to HTML [duplicate]

I have a template:
function useIt() {
var content = document.querySelector('template').content;
// Update something in the template DOM.
var span = content.querySelector('span');
span.textContent = parseInt(span.textContent) + 1;
document.querySelector('#container').appendChild(
document.importNode(content, true));
}
<button onclick="useIt()">Use me</button>
<div id="container"></div>
<template>
<div>Template used: <span>0</span></div>
<script>alert('Thanks!')</script>
</template>
You can try the code here.
This code basically copies the template(html5 templates does not render on your screen) into another div. This allows you to reuse the DOM.
Problem: The line "span.textContent = parseInt(span.textContent) + 1;" changes the template code directly. I need to manipulate the content DOM and clone it into the container, without changing the template. This is very important since if I want to reuse the code, I need it to stay the same.
I have tried multiple ways to use jQuery to mimic the above javascript code, but I can't manage to figure it out. It would be better if there is a jQuery way.
If you NEED to use the new <template> tag, then you are mildly stuck . . . your cleanest alternative is to use importNode to bring in the content and then modify it after it's been appended.
Assuming that the templated code is realtively small, this should happen fast enough that you would never notice the difference in approach, though, in this specific example, the alert(), would delay the change of the content, so you would see "0", until you clicked "Okay", and then it would update to "1".
The code change for that would be:
function useIt() {
var content = document.querySelector('template').content;
var targetContainer = document.querySelector('#container');
targetContainer.appendChild(document.importNode(content, true));
var $span = $(targetContainer).find("div:last-of-type").find("span");
$span.text(parseInt($span.text() + 1));
}
If you are not married to the idea of <templates>, you could use jQuery's clone() method to do what you want to do, very easily . . . but, clone does not "see" the content of a <template>, due to the special nature of that particular element, so you would have to store the templated code some other way (JS variable, hidden div, etc.).
HOWEVER, this method will not work if you need to clone a script, the way that a <template> will. It will not trigger any script code in the "template container" element when the cloned version is created or appended. Additionally, if you store it in a hidden <div>, any script code in the "template container" element will trigger immediately on page load.
A simple version of the code for the clone() approach would look something like this:
function useIt() {
var $content = $("#template").clone();
var $span = $content.find("span");
$span.text(parseInt($span.text()) + 1);
$content.children().each(function() {
$("#container").append($(this));
});
}
Assuming that your template was:
<div id="template" style="display: none;">
<div>Template used: <span>0</span></div>
<script>alert('Thanks!')</script>
</div>
You could also move the <script>alert('Thanks!')</script> out of the template and into the script section (after you completed the "append loop"), to achive the desired alert functionality, if you wanted to.
It's an old question, but, did you try cloneNode(true)? It works on templates, as this:
var span = content.querySelector('span').cloneNode(true)
regards.

Changing inner HTML of a button with dynamic id

On a project I'm working on, a HTML file is defining a Javascript template used on selection buttons. All buttons have a "Change..." label that I want to localize (set dynamically). In other cases I'm searching for the element ID and setting the InnerHTML accordingly. But in this case, the ID of the buttons are defined dynamically. Is it possible to have a text element inside the button element, search for this element, and set its InnerHTML value?
<script id="optionSelectionTemplate" type="text/x-handlebars-template">
<div class="sub-section option-selection">
{{#if name}}<h4>{{name}}</h4>{{/if}}
<div class="current"></div><button class="button" id="{{id}}" data-action-id="{{id}}">Change...</button>
</div>
</script>
I've been searching this for a while now. But given that my forte is not web development, I'm not really sure what to search for...
You may be able to get the button element(s) by its class instead; for example:
var x = document.getElementsByClassName("button");
As you suggested, you can improve your selection's precision by first getting the 'optionSelectionTemplate' element(s) like so:
var x = document.getElementById("optionSelectionTemplate").getElementsByClassName("button");
Or if you prefer:
var x = document.getElementById("optionSelectionTemplate").getElementsByTagName("button");
Here are some links for more on these method:
https://www.w3schools.com/jsref/met_document_getelementsbyclassname.asp
https://www.w3schools.com/jsref/met_document_getelementsbytagname.asp
Depending on how dynamic your localization should become, you could also specify the text inside a (locale-dependent) CSS as in https://jsfiddle.net/1gws5kat/ :
[HTML]
<button class="button btn_change" id="{{id}}" data-action-id="{{id}}"></button>
[CSS]
.btn_change:before { content: "Change..."; }
In particular when dealing with a large number of identically-named elements (i.e. many "Change" buttons), this might be pretty handy.
You find those btns by this command:
var btnlist= $(':button')
This Camano get you all button in your html file, then loop ton in and apply your changing.
Before call this command, jquery must be install.

How do I removeAttribute() hidden from p2? doesn't seem to do anything as is

I'm trying to change the attribute of an object with removeAttribute to take away the hidden status of it but so far nothing seems to work.
My code seems to have no effect. Am I doing something wrong?
function changePage() {
document.getElementById.("p2");
p2.removeAtribute.("hidden") ;
}
I've also tried it all on one line as well like so
function changePage() {
document.getElementById.("p2").p2.removeAtribute.("hidden") ;
}
I've never seen the use of dots before opening parentheses.
E.g.
document.getElementById.("p2").p2.removeAtribute.("hidden") should be document.getElementById("p2").removeAtribute("hidden")
(You are also referencing the element by id after you just retrieved it, which is unnecessary.)
Your first example didn't work because you retrieved the element and did nothing with it, then tried to access a p2 variable that wasn't declared. Again, you also have the . before parentheses.
Here's the js example:
function changeVisibility()
{
var p2 = document.getElementById('p2');
switch (p2.style.visibility)
{
case 'hidden':
document.getElementById('p2').style.visibility = 'visible';
break;
case 'visible':
document.getElementById('p2').style.visibility = 'hidden';
break;
}
}
<div id="p2" style="visibility:hidden">
test
</div>
<br />
<button onclick="changeVisibility()">
change visibility with basic js
</button>
And here's the jQuery example:
function changePage()
{
$('#p2').toggle();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="p2" style="display:none">
test
</div>
<br />
<button onclick="changePage()">
change visibility with basic js
</button>
The basic JS version uses the visibility style, and you can see that it doesn't collapse the element, it only makes it invisible.
jQuery has a nice built-in .toggle function that changes the display of the element. If it is hidden, it collapses the element. When the element is displayed, it is re-assigned whatever the display style is for that element. Building that in basic js would take a lot more work, as you are then tracking state (if you want to make the method reusable). You can make jQuery work similarly to the basic js version if you use the css properties, but toggle is quite nice and simple.
Your main issue is that you were mixing the getting of the element with methods that are only available on jQuery objects. I suggest reading the jQuery tutorials for basic accessors, which can get elements by id, class name, etc.

meteor.js - pass id of element clicked to a collection

I've built a page with 3 elements, each of which looks like this:
<div class="col-md-4 event-type">
<a href="{{ pathFor 'step2' }}" id="eventchoice" name="eventchoice" value="corporate">
</a>
</div>
I'm trying to pass the value or name or id of the the <a> element on to a collection using the following code:
EventsController.events({
'click #eventchoice' : function(event) {
console.log(event.target.getAttribute("id"));
console.log(event.target.getAttribute("name"));
console.log(event.target.getAttribute("value"));
var eventchoice = event.target.value;
var params = {
eventchoice: eventchoice
}
//Insert Event
Meteor.call('addEvent', params);
FlashMessages.sendSuccess('Event Added');
}
});
I added the console.log's to see if I can get the id/name/value of the <a> element, but the console outputs 'null' for all of these. Therefore, there is nothing to pass to the collection in the eventAdd method.
I don't believe the problem is with the EventsController, the addEvent method or the Events collection. Any ideas how I can pass these values through?
Thank you for your help!
I think there must be something wrong with your controller then, because if you check the Meteorpad here, it works just fine.
Although you might want to use a class instead of an id if you have many similar elements.
There are several ways of solving your problem but the way I consider as "The Meteor Way" is to use a separate template for every choice (or just use #each loop), if you do that your "this" inside the event code will contain the values you need in your scope, so you won't have to rely on the event.target for them.

Set div background color without using ID

Is possible change color of background my div using JavaScript without using ID? And how?
Html code is:
<div class="post" onmouseover="test(this)">
JS code is:
function test(item){
alert("Hi :-)");
}
Have you tried
function test(item){
item.style.backgroundColor = "red";
}
Since item is the actual div you're triggering this event on you won't need an ID to style the element.
A really easy (inline) solution would be the one below.
<div class="post" onmouseover="javascript:style.backgroundColor = 'red';">
Content blabla
</div>
I would personally rather do all of this inside a JS file but hey this works too.
You can loop through the DOM with JavaScript, but you'll have a better time of it if you're using JQuery. You'll want to invest some time learning about selectors:
http://api.jquery.com/category/selectors/
http://www.w3schools.com/jquery/jquery_ref_selectors.asp.
You'll be looking for something like:
function test(){
var element = $('div');
}
As people have shared in the comments, without a unique identifier, you'll have a rough time, especially as new elements are added to the page.

Categories