Angular / HTML clear input events - javascript

I am working on an Angular app and I seem to have stumbled upon a small bug/problem. I have 4 clickable areas in my html and each click calls a function of the component's .ts script. So far, so good. I want to make each area only be clickable once, however this doesn't seem to work the way I am doing it (and I do not quite understand why).
clicked(event: Event): void {
// Get coordinates of clicked cell
var elementId: string = (event.target as Element).id;
if(this.answersGiven.includes(elementId)) {
console.log("included");
return;
}
this.answersGiven.push(elementId);
And the html
<table>
<tr>
<td id="A1" (click)="clicked($event);">
</tr>
So after the first click, the answer should be pushed into the array which is working just fine. However after the second click on the same cell it is not jumping into the if condition. When clicking a third time on the same cell, it works however. When i log the events, the second time I only get "" instead of the element id. My guess is that this could have something to do with some sort of buffer or that the button is pushed down and stays down but I couldn't find anything realted to that.
Glad for any help, thank you :)

You should try this:
HTML:
<table>
<tr>
<td (click)="clicked($event, 'A1');">
</tr>
TS:
clicked(event: Event, cod: string): void {
// Get coordinates of clicked cell
var elementId: string = (event.target as Element).id;
if(this.answersGiven.includes(cod)) {
console.log("included");
return;
}
this.answersGiven.push(cod);
the Angular way of build your HTML have probably changed your <td id="A1", check into your browser developer tool if the ID keeps the same.

Related

JQuery/Javascript my function is not running when pressing button

I have a button, when I click I want it to get all data from the row. My .php file (i also have php code not included here) looks like so (I trimmed out the table for stackoverflow)
<tr class='rowdata'>
<td>Bob</thd>
</tr>
<input type='submit' class='getRow' value='ClickMe'>
<script>
$(".getRow").click(function() {
var rowOfData = $(this).closest(".rowdata");
alert(rowOfData.text());
});
</script>
Right now I click and nothing happens. Any ideas? The . prefix means it is searching for class.
Well first, have you checked your developer's console (F12) to see if you have any errors. Are you sure you've referenced the JQuery library.
Next, even with JQuery referenced, .closest() is going to search the ancestor elements of the element you call it on. If your button is not a descendant of the element you wish to find, you won't find it.
Now, assuming that .closest() does find your row, you are then asking for the .text() in the entire row. This may be what you want, but it's seems more likely that you'd want data cell by cell.
Also, your button is a submit button which is used for submitting form data, but it doesn't appear that that's what you're doing here. If that's the case, use a regular button.
And, your HTML isn't valid as you have a bad closing tag for your cell.
So, correcting all that:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr class='rowdata'>
<td>Bob</td>
<td>Smith</td>
<td><input type='button' class='getRow' value='ClickMe'></td>
</tr>
</table>
<script>
$(".getRow").click(function() {
var rowOfData = $(this).closest(".rowdata");
alert(rowOfData.text()); // Gets all the text in the row
alert($("td:first-child", rowOfData).text()); // Gets just first cell
});
</script>

Drag and drop players in a results table inside form to send to PHP (using DragulaJS)

I'm developing the front-end of an app to track tournaments. In one page, the user needs to update the tournament result by dragging a player from a list on the left inside the final results table on the right, that I'll send to a PHP backend for processing (I'm not developing the backend, just need to send the correct data via POST). My requirements are:
Have a list of players
Have a results table with fixed positions in each row (one row for 1st, one row for 2nd).
Each position will have 4 related inputs, all named position-1-NAME, in the same row, but different columns
The user should be able to drag players into each position
One player can only be in one position, and each position can only have one player
When a player is placed in the table, he should be removed from the list
I've tried several approaches but the one that came close is using the Dragula JS plugin.
Then, I create the list of players with an ul with the id to make it a container in Dragula:
<ul id="players-container">
<li>
Player 1
</li>
</ul>
Then, I have a table inside a form tag, and the name of the fields are all named according to the position, like position-1-name-of-the-input:
<form method="POST" action="file_to_process_form.php">
<thead>
<th>Position</th>
<th>Player</th>
...
</thead>
<tbody>
<tr>
<td>
1st Position
</td>
<td class="target">
<input type="text" name="position-1-player-name" value="" hidden>
</td>
<td>
...other inputs
</td>
</tr>
</tbody>
Then, in JavaScript, I made a hack to grab the text() from the li being dragged and put it inside the value attribute of the input of the table, so that I can send the name of the player in the first position to the backend. The code:
dragula([document.querySelector('#players-container'), document.querySelector('.target')], {
isContainer: function(el){
return el.classList.contains('target');
},
revertOnSpill: true
}).on('drop', function(el, target, source, sibling){
elValue = $(el).text();
$(target).find('input').attr('value', elValue);
});
So far, this is working with some bugs:
I can drop two players in the same td, and they will show both dragged li in the UI, but the form will only have the value of the last dropped player.
If I drag the player into all positions, one after another, all inputs will have the value of his name until I drag another player into that position.
So, I want to accomplish a couple of things:
Allow only one player inside each td class="target". I've tried to disable the td by removing the .target class but then I can't move the player again after being dropped.
Remove the value of the input when I drag the player out.
I know this is a bit of a hack but I don't have a lot of experience with JS/jQuery and this is the only solution that remotely works so far.
My questions:
How can I prevent multiple players form being dragged to the same td with Dragula or JS / jQuery code?
[SOLVED -- see edit] How can I remove the value of the input when I drag a player OUT of the td?
Do you know a better way to implement these requirements to recommend?
EDIT
I've managed to solve the question 2 by adding the following code:
dragulaObject.on('drag', function(el, source) {
$(source).find('input').attr('value', '');
});
So, after I posted the question I managed to hack away some solutions to the bugs/questions 1 and 2:
To prevent more than one player on the same position, I added the following code to the options in the dragula object initialization:
accepts: function(el, target, source, sibling) {
if($(target).attr('class') == 'target' && $(target).find('li').length <= 1) {
return true;
} else {
return false;
}
}
The first condition is there to allow the player to be dragged back to the list after being put in one position, since the list contains more than 1 li and, without the first condition, would invalidate the return to list drag.
There are still some animation bugs (the player being dragged briefly shows inside the position with another player, but the drag is not completed when dropped).
To solve bug/question 2, I added the following code (the same as edited in the original answer):
dragulaObject.on('drag', function(el, source) {
$(source).find('input').attr('value', '');
});
So, the full code for the Dragula object is:
dragula([document.querySelector('#players-container'), document.querySelector('.target')], {
isContainer: function(el){
return el.classList.contains('target');
},
revertOnSpill: true,
accepts: function(el, target, source, sibling) {
if($(source).attr('class') == 'target' || $(target).find('li').length <= 1) {
return true;
} else {
return false;
}
}
}).on('drop', function(el, target, source, sibling){
elValue = $(el).text();
$(target).find('input').attr('value', elValue);
}).on('drag', function(el, source) {
$(source).find('input').attr('value', '');
});
Not the prettiest code, but it did solve the problem. Hope it helps others trying to do similar things.

How to mark multiple elements without clicking in angular?

I have the following code:
<table>
<tr ng-repeat="minute in hour.minutes track by $index">
<td class="{{minute.class}}" ng-mousedown="setTdCol(hour, minute)" > </td>
</tr>
</table>
setTdCol just changes minute.class causing the cell to change its background color.
My goal is to allow the user to mark multiple cells by pushing the mouse button once and then moving above the cells.
That is why I used ng-mousedown instead of ng-click, but still I have to release the mouse and click each column. What has to be changed?
Try to build your logic together with ng-mouseover and ng-mouseup.
For example you can set a boolean variable mouseDown to true with ng-mousedown and set it to false with ng-mouseup. That way in your ng-mouseover function you can check if the mouse is down or up and mark the elements you go over. You can for example store them in an array and if the element exists in that array on hover - remove it. Or set them to active / inactive with boolean ... etc.
Hope that helps you :)
You want to know when the mouse is down on the table and when it is, which minutes its hovering above. You can set a flag to indicate if the mouse is down on the table that will vary when the table's ng-mouseup and ng-mousedown are invoked, and give an ng-mouseover function to each cell that will check if this flag is true.
<table ng-mousedown="isDown = true" ng-mouseup="isDown = false">
<tr ng-repeat="minute in hour.minutes track by $index">
<td ng-style="minute.class" ng-mouseover='setTdCol(hour, minute)'>aaa</td>
</tr>
</table>
In the example above, isDown is the flag. Now you just need to wrap setTdCol function in an if that checks if is down is true. just don't forget to initialize $scope.isDown in the controller
...
$scope.isDown = false;
$scope.setTdCol = function(hour, minute) {
if($scope.isDown) {
...
}
};
...

Toggle with ! operator not working on page load JavaScript

I have an onClick (using angular.js ng-click) where i have to toggle color of a table row with on click.
This is the initial implementation.
<tr>
<td ng-class="{'setType': types.isTypeSet('TYPE') == true}" ng-click="types.setType('TYPE')">
<img class="typebox-img" src="">
<div class="typebox">TYPE</div>
</td>
</tr>
where 'type' is the type of table row and 'types' is the angular controller.
types.setType(type):
...
this.types[type] = ! this.types[type];
...
while this toggles values from the second click on, it doesnt change the value on the first click.
I implemented the functionality using the if-else statement, but cant figure out why this wont work as it is a pretty basic thing to do.
this.types[type] is set to false as default.
Could someone explain why is this happening..
It doesn't surprise me that this doesn't work:
ng-click='types.setType('type')
Use " for the inner quotes to make the parser understand what you're trying to do (or the other way around):
ng-click='types.setType("type")'
Incidentally, you don't need a function to do this. Just initialize in your controller a bool:
$scope.toggle = true
And use in your view like this:
ng-click='toggle = !toggle'

how to capture onclick for wicket jquery ui spinner

How can I capture the onclick event for the up & down buttons on a spinner component from JQuery?
I am able to capture the onchange for the associated textfield with the following code, but the up & down spinner buttons are not triggering the event:
Spinner<Integer> psbBudget = new Spinner<>("psbBudget", new PropertyModel(psb,"psbBudget"), Integer.class);
psbBudget.add(new AjaxFormComponentUpdatingBehavior("onchange") {
#Override
protected void onUpdate(AjaxRequestTarget art) {
Integer inputS = (Integer) getFormComponent().getConvertedInput();
BigDecimal spinnerTime = BigDecimal.valueOf(inputS);
unallocatedTimeMap.put(psb, unallocatedTimeMap.get(psb).subtract(spinnerTime));
art.add(budgetListViewContainer);
}
});
listItem.add(psbBudget);
li.add(new Label("remainingBudgetLabel", new Model(unallocatedTimeMap.get(psb))));
Just to make it more difficult on myself, this spinner is contained in a ListView as the number of budget items is variable. I am getting the remainingBudgetLabel to reflect the changes that are made within the text field, but not the changes made using the spinner buttons!
I have started exploring injecting my own javascript with the following lines:
// behavior to capture changes made using spinner buttons (doesn't work!!!)
add(new Behavior() {
#Override
public void renderHead(Component component, IHeaderResponse response) {
super.renderHead(component, response);
response.render(OnDomReadyHeaderItem.forScript("$('.ui-spinner-button ui-spinner-up ui-corner-tr ui-button ui-widget ui-state-default ui-button-text-only').click(function() {$(this).siblings('input').change();})"));
}
});
Here is the relevant section of the declared html:
<table>
<tr>
<td/>
<th>Budget</th>
<th>Remaining</th>
</tr>
<tr wicket:id="budgetListView">
<th wicket:id="budgetLabel">Budget
</th><td><input wicket:id="psbBudget" type="text" style="width:3em" maxLength="2"/>
</td><td wicket:id="remainingBudgetLabel"/>
</tr>
</table>
So I guess this is somewhat of a two part question:
1 - Is there any hope of this javascript injection working (I am just getting my feet wet with javascript) or is there a way to do this more correctly within Wicket?
2 - If javascript is the only way, how can I correctly find the elements when I can't control the id attribute of the generated jquery (or can I control that somehow?)?
I am using the wicket-jquery-ui 6.2.1 library with wicket 6.6.0. Thank you.
EDIT
The generated html I posted previously (now removed) was from right clicking and selecting viewSource, but does not show the actual generated html from jquery. Please see below for a screenshot from the F12 Developer Tools in IE9 that shows the generated html for the spinner includes the original <input> plus two generated <a> tags for the spinner buttons.
I just saw this post...
Just to say that you had 2 other options:
1/ You have you own extended spinner with:
#Override
protected void onConfigure(JQueryBehavior behavior)
{
super.onConfigure(behavior);
behavior.setOption("onspinstop", this.onStopBehavior.getCallbackFunction());
//onStopBehavior is an JQueryAjaxPostBehavior, see how AjaxDatePicker works for instance
}
The second option is to ask for an AjaxSpinner, because it makes sense, either through the github project or the google group:
https://github.com/sebfz1/wicket-jquery-ui/
http://groups.google.com/group/wicket-jquery-ui/
Best regards,
Sebastien.
As much as I hate to answer my own question, here it is:
I was able to capture the events with the following code. The "onchange" captures the event when someone manually enters a number in the field, the "onspinstop" captures the event after the component has been updated by clicking the up/down arrow:
Spinner<Integer> psbBudget = new Spinner<>("psbBudget", new Model(allocatedTimeMap.get(psb)), Integer.class);
psbBudget.add(new AjaxFormComponentUpdatingBehavior("onchange") {
#Override
protected void onUpdate(AjaxRequestTarget art) {
Integer input = (Integer) getFormComponent().getConvertedInput();
// Do whatever with updated input //
art.add(remainingBudgetLabel,remainingBudgetLabel.getMarkupId());
}
}
psbBudget.add(new AjaxFormComponentUpdatingBehavior("onspinstop") {
#Override
protected void onUpdate(AjaxRequestTarget art) {
Integer input = (Integer) getFormComponent().getConvertedInput();
// Do whatever with updated input //
art.add(remainingBudgetLabel,remainingBudgetLabel.getMarkupId());
}
}
I was able to figure this out after looking at the API documentation for the JQuery UI Spinner component then trying every possible combination of the event strings. To do this correctly you have to put the string all in lowercase and add "on" string to the beginning of the event name.
One additional thing that I learned during this exercise was that I can update (I think I am actually replacing them?) individual components within a listview by calling art.add(component, component.getMarkupId());. This is SO much better than what I was doing before with listView.setList(updatedList) and art.add(listViewContainer);

Categories

Resources