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

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.

Related

Calling a function onclick in Svelte

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

Replacing the onclick parameters for a link in a cloned table row

I have a button in a table that is cloning the current row and then clearing some of the values (which works without issue). However, one of the cells has a link that has an onclick event with some parameters
<td class="srcbtn"><a class="grid_button" onclick="functionName('#MyLiteral', 'STUDY=ABC&SURID=3&SID=ABC01&LANG=en-US&RID=4e60fd3d-1ab4-e711-80ec-0050568a179a');"><img src="imgsrc.png" alt="img" style="border-width:0px;"></a></td>
I'm able to grab the button
if ($(this).hasClass( "srcbtn" ) ) {
var btn = $(this).find('.grid_button')[0];
console.log(btn);
}
Which gives:
<a class="grid_button" onclick="functionName('#MyLiteral', 'STUDY=ABC&SURID=3&SID=ABC01&LANG=en-US&RID=4e60fd3d-1ab4-e711-80ec-0050568a179a');"><img src="imgsrc.png" alt="img" style="border-width:0px;"></a>
What I need to do however is either remove one of the parameters in the onclick or even just change the parameter name, but the other parameters need to be remain. The function itself creates an iframe in a Literal control and builds the URL with the parameters, the function and parameter name is created dynamically from some database values, so I can't just clear and recreate it.
In this case, the &RID=4e60fd3d-1ab4-e711-80ec-0050568a179a needs to either be stripped out or even just replace the &RID= to &XRID= or similar so the code further along doesn't see a RID parameter passed.
I thought I could use .replace('&RID=', '&XRID=') but get an error that replace is not a function. So then I tried .text thinking I could use the replace on the text, but the text returns blank.
It'd be helpful if someone could show me how to modify the text of the onclick.
thanks
It will be much better for you to use so called "live" events from jQuery and HTML5 data- attributes. In this case your HTML code may look something like this:
<td class="srcbtn"><a class="grid_button" data-target="#MyLiteral" data-study="ABC" data-surid="3" data-sid="ABC01" data-lang="en-US" data-rid="4e60fd3d-1ab4-e711-80ec-0050568a179a"><img src="imgsrc.png" alt="img" style="border-width:0px;"></a></td>
and then into your script you may use something like:
$('table').on('click', '.grid_button', function (ev) {
ev.preventDefault();
var $e = $(this);
functionName($e.data('target'), $.param({
STUDY: $e.data('study'),
SURID: $e.data('surid'),
SID: $e.data('sid'),
LANG: $e.data('lang'),
RID: $e.data('rid')
}))
});

How do I retrieve data from within a handlebars loop and use it within backbone model?

I have a problem that has left me scratching my head for days. My knowledge of JavaScript is not great, I'm still learning, and to top it off I'm working on a project where I'm forced to use handlebars, Marionette and other stuff I'm not familiar with.
I have a handlebars template which looks like this:
{{#if images}}
{{#each images}}
<div class="image-thumbnail">
<i class="delete-button" style="cursor:pointer" id="delete-button-id" data-imgid="{{id}}"></i>
<img src="{{thumbnail}}"/></a>
</div>
{{/each}}
This all looks fine when the page loads, no problems there. If I put {{id}} between <i>{{id}}</i> then the value is output correctly to the browser. The problem I'm having is accessing that id from a pop-up which I'm generating using:
deleteImage: function(event) {
new DeleteView({model: new Backbone.Model()}).render().$el.appendTo('body');
},
I've tried adding the following:
new DeleteView({model: new Backbone.Model({ imgid: imageID })}).render().$el.appendTo('body');
And setting imgid using:
var imageElement = document.getElementById('delete-button-id');
var imageID = imageElement.getAttribute('data-imgid');
Unfortunately this only gets the last imgid and it's the same for every one. The page is basically a list of photos which are generated from the handlebars loop. There can be dozens on the page at once, and the imgid I get when the pop-up fires needs to be specific to the one I clicked.
My main view for the page where the images appear:
var ThumbnailView = Marionette.ItemView.extend({
template: getTemplate('profile/thumbnail'),
className: 'main-gallery',
events: {
'click .delete-button': 'deleteImage'
}
... more code follows ...
Can anyone tell me what I'm doing wrong? I need to get the correct dynamically-generated imgid from data-imgid="{{id}}" but I'm only getting the same one each time.
Any help would be greatly appreciated.
Thanks in advance!
The reason why you're getting the last ID each time is because you are selecting the element via the ID attribute:
document.getElementById('delete-button-id');
and unfortunately, your template has id="delete-button-id" on each of the <i> elements being rendered, thus when you try to do document.getElementById it will always return the last element with that attribute. The id attribute (unlike class) is intended to be unique, and according to W3C it must be unique in the document. If it isn't, it can cause issues like the one you're seeing (see here for more info: https://developer.mozilla.org/en-US/docs/Web/API/Element/id, https://www.w3.org/TR/html401/struct/global.html#h-7.5.2).
To fix this, remove the id attribute from the <i>. Also remove the dangling </a> as well. Your template should now look like:
{{#each images}}
<div class="image-thumbnail">
<i class="delete-button" style="cursor:pointer" data-imgid="{{id}}"></i>
<img src="{{thumbnail}}"/>
</div>
{{/each}}
Now when you're trying to select the element in deleteImage, you can do so via jQuery/Marionette by doing:
var imageId = this.$(event.currentTarget).data('imgid');
Or if you're keen on using plain JavaScript, you can obtain the ID like so:
var imageId = event.currentTarget.getAttribute('data-imgid');
And that should do it. You can play around with this JSBin to see how it will work:
https://jsbin.com/fotiqisoye/edit?html,js,output
the marionette way to restructure this solution would be to replace your each loop with a CompositeView, and feed it a collection of models, which will each render an ItemView, which will be represented in your dom as a single line-item of image.
when you click delete on that image, the ItemView receives the event, and the model.id passed into it will be correct.
more on this here: http://marionettejs.com/docs/v2.4.7/marionette.compositeview.html
hope this helps

selectmenu ('refresh', true)

I get form from zend framework site and put it in response in new file in function written by jquery mobile, but I get this error:
uncaught exception: cannot call methods on selectmenu prior to
initialization; attempted to call method 'refresh' .
Code of function this file:
function addItem(id) {
$.ajax({
url:'http://zf.darina.php.nixsolutions.com/order/index/create-order-mobile',
dataType:"jsonp",
data:{id_good:id},
success:function (resp) {
console.log(resp);
$('.product-table').empty();
$('.product-table').append(resp.prod);
$('.product-table').append(resp.form);
$('.add-order-btn').button();
$('.mob-size').selectmenu('refresh', true);
$('#block').page();
}
})
}
Force initialize the selectmenu(s) first:
$('.mob-size').selectmenu(); // Initializes
$('.mob-size').selectmenu('refresh', true);
or use this for short
$('.mob-size').selectmenu().selectmenu('refresh', true);
In my case, if I was not initializing the select before invoking the 'disable' method I got the error, while if I was initializing it, the select didn't disable but duplicate itself - I tried to select the object by TAG NAME instead of by CLASS or ID NAME,
$('select').selectmenu('disable');
instead of
$('.select-class-name').selectmenu('disable');
and it worked without forced initialization
you do this in your custom refresh delegation function:
var w = $("#yourinput");
if( w.data("mobile-selectmenu") === undefined) {
// not initialized yet, lets do so
w.selectmenu();
}
w.selectmenu("refresh",true);
according to enhancement resolution here
I found the same problem, but a more involved solution. When jqm wraps the select element, it puts it in a <span> element with the same class list as the select element. I changed my reference to it so that instead of reading:
row.find(".selectCompletion").selectmenu("disable");
it now reads:
row.find("select.selectCompletion").selectmenu("disable");
Specifying that jquery should only find the select element matching the class name, rather than all elements in .row that match the class name, solved the problem.
This happened to me when cloning existing select element in order to duplicate the original section multiple times.
Calling 'refresh' for the original element, worked fine, while calling it for the cloned sections was leading to the error appearing in the question.
However, calling selectmenu() was causing a 'vandalisation' to the form, as can be seen in the following image:
Explanation: top = original. bottom = vandalised cloned element right after calling selectmenu.
Solution:
The following code solved this vandalisation problem:
cloned_elem.find('select[name=MyClass]').selectmenu().selectmenu("destroy").selectmenu();
This is not an ideal solution because we must call the first selectmenu() in order to call selectmenu("destroy"), so I would be glad to hear of a cleaner solution.

jQuery load issue. Don't know how to approach this AJAX call

$("[littleBox]").load("ajax.php?eid="+$(this).attr("littlebox"));
the $(this).attr("little box") portion of the code returns undefined.
I'm trying to get the individual attribute of the initial $("[littleBox]").
this particular line of code is called as the soon as the document is ready.
when I put predefined values, such as
$("[littleBox]").load("ajax.php?eid=1");
It works as expected. Unfortunately, I need it to load specific content based on that element's attribute. Any idea how to make this work?
Loop through all items with proper this:
$("[littleBox]").each(function() {
var $this = $(this)
$this.load("ajax.php?eid="+ $this.attr("littlebox"));
});
this will not refer to $("[littleBox]") in that context, you'll have to repeat the selector - or select the element already and re-use it:
var $box = $("[littleBox]");
$box.load("ajax.php?eid=" + $box.attr("littlebox"));
post yout html that cotnain attr "little box" in it.
is it like
<a attr="little box" id="test">test<a/>
then it work like
$('#test').click(function(){
alert($(this).attr('little box'));
});

Categories