prototype : onclick remove previous element - prototypejs

i have html as below in which onclick of <a> i want to remove the text box above it.
<input class="sku-box" class="input-text validate-number" type="text" title="file-number" name="sku[]">
<a value="remove" onclick="remove()" href="javascript:void(0);">remove</a>
<input class="sku-box" class="input-text validate-number" type="text" title="file-number" name="sku[]">
<a value="remove" onclick="remove()" href="javascript:void(0);">remove</a>
my solution to this, i changed the <a> tag to this.
remove
and my prototype function look like this
function removefield(ele)
{
$(ele).previous().remove();
ele.remove();
}

You have several options for observing click events, and usually I wire up click events after the dom is loaded using something like:
document.on('click', 'a', myFunction.BindAsEventListener())
The above statement sets you up for observing all click events occurring for the a element firing up the function myFunction. Once you have this established you can then either trap the event or simply allow it to bubble up or do both, trap and bubble up the event.
However, with the direction you are going there you would be better off to pass the identity of your a tag to the remove function, then it is easy to remove the previous element. So you would have:
<a id="a_tag1" value="remove" onclick="remove('a_tag1')" href="javascript:void(0);">remove</a>
Then your function remove might look something like this:
function remove(a) {
// prev element
var elm = $(a).previous('input');
// remove it
if(elm)
elm.remove();
}
This is very basic and in reality you would need to do things to guarantee that the previous input element you are grabbing is associated with the a element you clicked. You could do this by agreeing on a new data-xxxx element tag or an arbitrary class name you can use to compare the elements. For example, your a tag might look like:
<a data-group='monkeys'>...</a>
And the cooresponding input tag might look like:
<input data-group='monkeys'>...</input>
Then, in the above code where you call previous on the a tag, you would construct your select to include a test on the data-group value that matches the current a tag.
Karl..

Related

Ui-tabset and bootstrap-daterangepicker not working together?

I have an application where I am using ui-bootstrap-tabs. documentation here. With the ng-bs-daterangepicker.
The behavior I am observing is that whenever I put the daterangepicker inside the ui-tab. It is not able to catch the events attached to it.
But when I move that input tag outside the ui-tabs, it's able to catch the events associated with it.
I have created a working plunker to highlight my issue.
<body ng-app="myApp">
<div ng-controller="testController">
<uib-tabset>
<uib-tab index="0" heading="Drivers"></uib-tab>
<uib-tab index="1" heading="Charts">
<input class="btn btn-danger" type="daterange" id="daterange1" ng-model="dates" format="DD MMM" ranges="ranges" />
</uib-tab>
</uib-tabset>
<!-- <input class="btn btn-danger" type="daterange" id="daterange1" ng-model="dates" format="DD MMM" ranges="ranges" /> -->
</div>
</body>
Here there are two input tags. One inside the uib-tab and other outside it.
$scope.dates = {
startDate: moment().startOf('day'),
endDate: moment().endOf('day')
};
$scope.ranges = {
'Today': [moment(), moment()],
'Yesterday': [moment().subtract('days', 1), moment().subtract('days', 1)],
'Last 7 days': [moment().subtract('days', 7), moment()],
'Last 30 days': [moment().subtract('days', 30), moment()],
'This month': [moment().startOf('month'), moment().endOf('month')]
};
$('#daterange1').on('apply.daterangepicker', function(ev, picker) {
console.log(picker.startDate);
console.log(picker.endDate);
});
The event apply.daterangepicker is not called when I activate the inside input button but is called when I activate the outside one.
My approach
I am guessing it's not a scope issue as highlighted in some posts. Because if it was that, then how come even the date is being populated.
Another thing could be the Known issue column which says
To use clickable elements within the tab, you have override the tab
template to use div elements instead of anchor elements, and replicate
the desired styles from Bootstrap's CSS. This is due to browsers
interpreting anchor elements as the target of any click event, which
triggers routing when certain elements such as buttons are nested
inside the anchor element.
maybe somehow this is stopping the event propagation. I am stuck at this point and can't think of a solution on how to fix it. Hoping the community would help here...
In case of $('#daterange1').on the object to which the event if getting attached must exist at the moment when .on() is invoked.
When daterangepicker is initialized inside Tabs component you could attach event like this:
$("body").on("apply.daterangepicker", "#daterange1", function(e,picker) {
console.log(picker.startDate);
console.log(picker.endDate);
});
Modified plunker

Angular 2 - Using pipe in (click) event

My question is probably simple but just can't find the way to use pipe within an event like (click) for example. Something like this:
<button (click)="quizAnswers(answer?.texte | translate | async)"></button>
I always get an error. I tried to wrap it with () or {} or []...
There are some workaround like putting the content in an attribute and then get it on the event with this.attribute but I'm sure there is a proper way !
Thanks in advance for your help
A workaround would be to call your pipes in the click handler function instead:
function quizAnswers(answer)
{
let translatePipe= new TranslatePipe();
...
return translatePipe.transform(answer?.texte);
}
I just got through this same issue. Action expressions can't contain the async pipe. However, you can use a hidden <input> element to hold the latest value of the promise/observable stream, and then access that value anywhere.
<input #dummy style="{display: none}" type="text" value="{{ myAsyncSource | async }}">
<a (click)="myFunction(dummy.value)">{{ dummy.value }}</a>
For your case of <button> there's actually a one-line solution that eliminates the need for the dummy <input>, posted in this solution:
<button type="button" #item value="{{i$ | async}}" (click)="buttonClicked(item.value)">BUTTON</button>

Why does this Web2Py ajax call fail to return the value of a variable?

Here is the relevant snippet from my Web2Py view:
{{for candidate in rows:}}
<div class="well col-sm-12">
<button type="button" name="up_button" onclick="ajax('{{=URL('default', 'arrow_button_callback')}}', ['name'], 'target')" class="fa fa-caret-up arrow-up fa-4x"></button>
<span>{{=candidate.votes}}</span>
<button type="button" name="down_button" onclick="ajax('{{=URL('default', 'arrow_button_callback')}}', ['name'], 'target')" class="fa fa-caret-down arrow-down fa-4x"></button>
{{=IMG(_src=URL('photos',candidate.path_to_photo), _alt="Photo of Candidate")}}
{{=candidate.name}}
<div id="target"></div>
</div>
{{pass}}
And the relevant snippet from my Web2Py controller:
def arrow_button_callback():
response.flash = str(request.post_vars.name)
return request.post_vars.name
So why do I see the string "None" in my target div (and in my flash)?
Thank you for your help. I read chapter 11 of the Web2Py book and I'm still confused.
I really want to be able to pass candidate.id (depending on which row's button was pressed) and the button direction to controller variables. Please let me know if there's a better way to do this.
--Benjamin
From the web2py documentation (emphasis added):
ajax(url, [name1, name2, ...], target)
It asynchronously calls the url (first argument), passes the values of the field inputs with the name equal to one of the names in the list (second argument)...
In your code, your second argument is ['name']. However, there is no input field with the name "name" anywhere, so no "name" variable gets posted to web2py (therefore, request.post_vars.name is None, which is the default value returned whenever you attempt to get a variable that does not exist in request.post_vars).
In this case, because you are not placing any data in form input fields, you can simply ignore the second argument to ajax(). Instead, pass the relevant data via the URL itself:
{{url = URL('default', 'arrow_button_callback',
vars=dict(id=candidate.id, direction='up'))}}
<button type="button" name="up_button" onclick="ajax('{{=url}}', [], 'target')"
class="fa fa-caret-up arrow-up fa-4x"></button>
Then in the arrow_button_callback controller, you can access the candidate id via request.get_vars.id (or just request.vars.id). And you can access the arrow direction via request.vars.direction. Create a new URL for the "down" button, with direction='down'.

How to serialize a form with dynamically added inputs using jQuery?

I've read through a lot of questions addressing similar question but I can't get a grip on it, yet.
I have a simple HTML form just like
<form id="edit-items" name="edit-items" onsubmit="saveItems();">
<input type="submit" value="Save">
<input class="item" id="ei81" type="hidden" name="i[81]" value="1">
<input class="item" id="ei124" type="hidden" name="i[124]" value="1">
</form>
The two existing hidden inputs could be set upon document loading due to a prior save.
Now I have images (kind of a menu). If they are clicked a corresponding hidden input is appended to the form:
<img id="i37" class="clickable-item" src="items/i37.gif" title="item name" onclick="addItem(37,1)" />
The addItem function:
function addItem(id,n) {
var zitem = $("#e"+id);
if ( 0 in zitem ) {
if ( zitem.val() > 0 ) {
var newcnt = parseInt(zitem.val()) + n;
if ( newcnt <= 0 ) {
zitem.remove();
}
else {
zitem.val(newcnt);
}
}
}
else if(n == 1) {
var iform = $("#edit-items");
iform.append("<input class=\"item\" id=\"e"+id+"\" type=\"hidden\" name=\"i["+id+"]\" value=\"1\">");
}
}
This part all works correct, after clicking the image, my form looks like
<form id="edit-items" name="edit-items" onsubmit="saveItems();">
<input type="submit" value="Save">
<input class="item" id="ei81" type="hidden" name="i[81]" value="1">
<input class="item" id="ei124" type="hidden" name="i[124]" value="1">
<input class="item" id="ei37" type="hidden" name="i[37]" value="1">
</form>
which is exactly what I want. But then when hitting the submit button only the first two elements are submitted (the ones which have not been added dynamically).
Now, I read a lot about .bind and .live handlers but I am missing some point obviously. I tried to delete the onclick attribute on the images and to bind the .live to them since they are causing the new inputs:
$(".clickable-item").live("click", function() {
addItem($(this).attr("id"),1);
});
However, the ID is not transferred which is needed, though (hence no correct input is added). I learned that .live doesn't bind the handler to any elements but to the event.
Is it even possible to pass the element which has been clicked to the live handler?
Should the images even be watched by .live or should it be bound to something else?
The last thing I learned form another question here is that the inputs should be watched by .live, since they are dynamically added. But what kind of event I would attach? The inputs themselves are not clicked.
I would really appreciate any help as I am cracking my head and starting to get lost on that one.
Thanks in advance,
Paul
Regarding live() [docs]: this refers to the clicked element, so you can pass it to addItem with addItem(this, 1). This part of your code should work.
If you don't add or remove images dynamically then there is no reason to use live. You can just use click() [docs] (and yes, don't use onclick in the HTML).
But I see another problem:
The image id is i37. $(this).attr("id") will return this value.
In your addItem function you then take this value and perform string concatenation. The result will be $("#ii37") (note the two is).
The input element you create will have the id ii37 and not i37.
If you correct this to match it with the other elements like in your example (i.e. i37) , you will have problems because you have several elements with the same id (the input element and the image). If the image comes before the input field in the hierarchy, then $("#i37") will always select the image and you cannot call .val() on an image.
As I don't know what is the overall purpose of the code and what you want to do, I cannot give any suggestion how to improve this. Maybe it is enough to just change the prefix of the image and input field ids.
I learned that .live doesn't bind the handler to any elements but to the event.
That is not correct. .live() binds the event handler to the document root. Events, if not cancelled, bubble up the DOM tree, so they reach the root eventually. There, the event.target [docs] property is examined to determine the element that was clicked.

Best way to add a dynamic amount of elements to a form?

I have a complex form that has a static section and one that can have from 0 to many divs that containing radio buttons, textfields and textareas.
I'm wondering what's the best way to add elements to the section that has a variable amount of form inputs. I have a working solution, but it's probably not the best:
I use javascript to add a chunk of html code and append it to the div containing the variable amount of input fields. In the code sample below, my javascript code would do something like
Javascript
document.getElementId('dynamic_form_stuff').innerHTML += "<div id='element3'>Form stuff</div>";
HTML
<form>
<div id="static_form_stuff">
form fields
</div>
<div id="dynamic_form_stuff">
<div id="element1">
Radio buttons stuff
Text field stuff
Text area stuff
</div>
<div id="element2">
Radio buttons stuff
Text field stuff
Text area stuff
</div>
</div>
</form>
I think this largely depends on what you are doing elsewhere, and how many items you are adding, as well as how you want to add event handlers.
I tend to find it easier to use the DOM methods if I need to add event handlers, but if you are just adding to a form with a submit button, then using innerHTML is faster, as shown here: http://www.quirksmode.org/dom/innerhtml.html.
I would personally do something like:
var elem = document.getElementId('dynamic_form_stuff');
var div = document.createElement('div'); // create element
div.setAttribute('class', 'myclass'); // define attributes
elem.appendChild(div);
// and/or more code.....
This gives me more control in adding attributes and style there.

Resources