I am working on a admin page where you can list all the users. In a table you can see each user permissions.
I want to use a checkbox that automatically updates the database column value either to true or false by using ajax (according to a given permission represented by a badge checkbox).
I have found this badge checkbox. And the jsfiddle is here.
However, there is a problem. When there is more than one row, the checkbox functionality does not work anymore. Moreover, if you change the default id of any badge, this does not work any longer as shown now in this fiddle.
How can I make these badges work for several rows and with their own IDs?
For example, I want to assign id="user-{{id}}-permissionName" instead of id="success" for all the rows.
You could actually change the default id of any badge and It actually works if you change id but you need to change it's parent label element's for property too and it is used to target particular checkbox
For ex:
<label for="danger1" class="btn btn-danger btn-xs">Query
<input type="checkbox" id="danger1" class="badgebox"/>
<span class="badge">✓</span>
</label>
DEMO
When you have rows of repeating elements that may have multiple actions contained within it is generally simplest to store the data needed on the row itself. Then use classes or data attributes to define the types of controls.
<div class="row" data-id="{{id}}" data-permission="user-{{id}}-permissionName">
<input type="checkbox" data-action="delete" class="btn btn-delete">
</div>
JS
$(':checkbox').change(function(){
var $row = $(this).closest('.row'),
rowData = $row.data();
var action = $(this).data('action');
var id = rowData.id;
var permission = rowData.permission;
});
Related
I have a table with lots of rows
I have a filter to hide these rows based on the content of a child element (an input field) several levels down within the row
The input field within the row is wrapped several times. I can't manage to hide the row based on that inputs value.
Here's how a row looks:
<tr class="acf-row" data-id="row-13">
<td class="acf-field acf-field-date-picker acf-field-5de02ec006a2e" data-name="datum" data-type="date_picker" data-key="field_5de02ec006a2e">
<div class="acf-input">
<div class="acf-date-picker acf-input-wrap" data-date_format="dd.mm.yy" data-first_day="1">
<input type="text" class="input hasDatepicker" value="24.03.2020" id="dp1582735317447">
</div>
</div>
</td>
</tr>
Please note that there are more siblings on each level than I've put in here for readability. But the hierarchy is as displayed here.
Then I've got this input field to define what we want to filter:
<input placeholder="Datum filtern" type="text" id="datefilter" style="padding:5px; width:150px;">
And last but not least the jquery:
$( "#datefilter" ).change(function() {
var filterdate = $("#datefilter").val();
jQuery('.input.hasDatepicker').each(function() {
var currentElement = $(this);
var dateinfield = currentElement.val();
if( dateinfield !== filterdate){
$(this).closest('.acf-row').hide();
}
});
});
Currently it hides all the rows, not just those with a different value. What should happen is that only the rows get hidden where the value of #datefilter is different from the value of .input.hasDatepicker
I tried a few things like trying to use .parent().parent()... but didn't get it to work. Help would be greatly appreciated.
Here's a jsfiddle with the whole table including all siblings:
https://jsfiddle.net/59by3w7o/
UPDATE:
I think I can now say for sure the issue is 2 instances of the input element in each row. Here's a jsfiddle with only that and no noise:
https://jsfiddle.net/8k41xy6u/
How could I solve that? I tried playing with :first but couldn't get it to take the first within each .acf-row and not the very first in the whole document.
From the updated JSFiddle, a table row looks something like:
<tr class="acf-row">
<td>
<div class="acf-input">
<div>
<input class="input hasDatepicker" type="text" value="26.03.2020">
<input class="input hasDatepicker" type="text" value="10:00">
</div>
</div>
</td>
</tr>
And now the problem becomes clear. In the JS, .each() iterates over everything with the classes .input and .hasDatepicker. Both your inputs match that, so it will test both of them. If the value of the either one does not match your filterdate that row will be hidden. But the 2nd input value is a time, and that will never match a date, no matter what the date is - so every row will always be hidden.
There are 2 obvious ways to tackle this - 1) make the inputs distinguishable, so you can target just the date input in your filter comparison, OR 2) somehow target just the first input in the set of 2.
The first option (make them distinguishable) is by far the best, as the second relies on the layout of the HTML. It could happen in future that you'll do a redesign and the inputs won't be in the same order, or even in the same <div>, and then your JS will break. That might even happen without you doing it or even knowing about it if the HTML is autogenerated by some 3rd-party library (eg ACF/Wordpress), and a plugin update changes things. But if you can distinguish the inputs then you can target the right ones no matter where they are on the page.
To make them distinguishable, you could add a class, eg:
<input class="input hasDatepicker date" type="text" value="26.03.2020">
Then update your JS to target only those:
$('.input.hasDatepicker.date').each(function(i) {
If changing the HTML isn't an option, then you'll have to rely on and make use of position. Iterate instead over all div.acf-inputs, and find the first input in each:
$('div.acf-input').each(function(i) {
var dateinfield = $(this).find('input.input.hasDatepicker').first().val();
// ...
Working JSFiddle (of option 2).
My Website is meant to have several carts per user and they are listed and updated via AngularJS like this:
<tr ng-repeat="cart in carts|orderBy:orderByField:reverseSort">
<td>
<input type="radio" ng-model="form['cart_id']"
ng-value="cart.cart.cart_id" />
</td>
<td>{{cart.cart.alias}}</td>
<td>{{cart.cart.description}}</td>
<td>{{cart.cart.created}}</td>
</tr>
When I add another cart in $scope.carts it gets updated pretty well, but I am not able to let the new cart be preselected when it is shown.
I tried using adding ng-checked=true which did not work, adding an ID and setting .attr('checked','checked') in JQuery, but the element is not known at that moment.
I am using Angular 1.2.22, JQuery 1.9.0 and Bootstrap 2.3.2. So I am well aware it's pretty outdated, but as I am new here, I am not able to change it. Yet.
Radio buttons are pre-selected by setting their model to the defined value. To select the last item in the carts array:
var last = $scope.carts.length-1;
$scope.form.cart_id = $scope.carts[last].cart_id;
For more information, see
AngularJS <input type=radio> Directive API Reference
Use value prop to make radio preselected, like: value=<value of ng-model variable which you want to get preselected>
Refer to this: https://docs.angularjs.org/api/ng/input/input%5Bradio%5D
In this AngularJS controller for a pre-filled form, fetching the data is triggered by an event using $broadcast and $on. However, when the data updates, only some of the corresponding fields get updated in the view.
$scope.currentHouse = {};
$scope.$on('houseInfoLoad', function(event, data) {
$scope.currentHouse = data.houseDetail; //does not refresh the view
console.log($scope.currentHouse); //output is correct
//the next three calls refresh the corresponding fields in the view
$scope.changeGarageRadioValue($scope.currentHouse.hasGarage);
utils.setSelection($scope.houseKeywords, $scope.currentHouse.keyword.id);
utils.setSelection($scope.houseTypes, $scope.currentHouse.type.id);
});
changeGarageRadioValue() essentially does what it says, and utils.setSelection(list, id) adds a selected = true property to the element of the list that has the id. This has the effect of setting the value of a select field (using isteven's multi-select plugin).
The view has a few text fields bound to properties of $scope.currentHouse, as well as these radio buttons and select fields.
The result is that the text fields sometimes do not get updated, however the select and radio buttons do.
Here's what I tried unsuccessfully:
Wrapping everything in a $timeout();
Calling $scope.$apply() after setting $scope.currentHouse (throws an error saying that we are already inside an $apply())
Changing the initial definition of $scope.currentHouse from {} to an object with each of the fields set to null.
Can anyone see what I am missing, or how to force trigger the refresh?
EDIT : with extracts from the view :
A text field:
<label>ADDITIONAL DESCRIPTION</label>
<div>
<input type="text" ng-model="currentHouse.additionalDescription" class="input-mandatory" value=""/>
</div>
A multi-select:
<label>TYPE</label>
<div>
<div directive-id="houseType" multi-select input-model="houseTypes" output-model="currentHouse.type" button-label="text" item-label="text" selection-mode="single" default-label="Select" tick-property="selected" ></div>
</div>
The radio buttons :
<div><label>HAS GARAGE</label></div>
<div>
<div id="radiobuttonNo" ng-click="changeGarageRadioValue(false);">
NO
</div>
<div id="radiobuttonYes" ng-click="changeGarageRadioValue(true);" class="active">
YES
</div>
</div>
EDIT #2 as per Alok Singh's suggestion:
I tried putting data.houseDetail into $scope.currentHouse.house instead of $scope.currentHouse directly, and changing the view accordingly. Still no results.
$scope.currentHouse = data.houseDetail
You cannot get the updated value of currentHouse because its a model.
So change the above code i.e
$scope.currentHouse.house = data.houseDetail
I tried to google, but failed.
I want the element with an ID to be unique relatively to, for example, his parent, not to the document itself. Is there a way to do that?
Ok, since you need an example. I have a huge form, with tons of radio buttons and inputs, e.g.: 2 radio buttons with IDs. Each with label.
<input type="radio" id="foo" name="name">
<label for="foo">Never</label>
<input type="radio" id="bar" name="name">
<label for="bar">Daily</label>
I can not afford to change this setup.
And I have a button that clones (via .clone()) this form.
As you may guess, it all breaks, because IDs and labels are not unique.
Radio inputs can be placed inside labels. With this setup, you don't need an id for the radio to match the for of the label, and the label will work as expected (clicking it activates the radio input). This removes the need for you to create a unique for-id pair.
<label>
Here's teh label
<input type="radio" name="foo">
</label>
<label>
Here's another label
<input type="radio" name="foo">
</label>
The following is just a suggestion of an algorithm with some working code, there is logic missing from the question regarding how to determine where to insert the cloned element. I've modified the name of the controls since giving a control a name of name masks the form's own name property.
The id is generated based on the number of controls in the form with the same name. Perhaps you have some other algorithm.
function cloneRadio(control) {
// Create a document fragment for convenience
var frag = document.createDocumentFragment();
// Clone the control and add to fragment
var el = frag.appendChild(control.cloneNode());
// Get all the controls in the form with the same name
var controls = control.form[control.name];
// Give the new control an id of name + control count
el.id = control.name + controls.length;
// Add a label
var label = frag.appendChild(document.createElement('label'));
// Add text in label
label.appendChild(document.createTextNode('for ' + el.id));
// Link label to element
label.htmlFor = el.id;
// Add to end of form
control.form.appendChild(frag);
}
This assumes that you aren't removing any elements, that will mess with the numbering if you do. I've just put the cloned element at the end of the form, you'll need some way of working out where to put it but haven't mentioned it here.
Some related HTML:
<form>
<input type="button" value="clone foo"
onclick="cloneRadio(this.form.controlName[0]);">
<br>
<input type="radio" id="foo" name="controlName">
<label for="foo">Never</label>
<br>
<input type="radio" id="bar" name="controlName">
<label for="bar">Daily</label>
</form>
Edit: the OP totally changed his question after my answer. Please look at the edit history before assuming I was off topic
If you are tempted to use the same ID for multiple items, you need to use a class. You can target classes within specific parent nodes. For example, in jQuery:
var elem = $('.parentClass .childClass');
This would target only items of .childClass that are children of .parentClass. You could select other instances of .childClass with different parent elements by changing the parent element in the CSS selector.
var eleme = $('.otherParentClass .childClass');
I have some jquery code where I am trying to select a checkbox when the user clicks on a div. My fiddle is below:
http://jsfiddle.net/5PpsJ/
What i have come up with is this, but it is not selecting the checkbox inside of the span:
$('span[name="' + current + '"]').closest('input:checkbox[id="CB_Selected"]').prop('checked', true);
The full code is in the link
My question is how can i get the select box inside of the span based on its unique name and select it?
n.b I have commented out the hide functio0n in jquery to visually see whether the checkbox is selected or not
EDIT
My ID's are the same because I am working inside of ASP.NET and using a repeater to create the HTML shown in the fiddle. Inside of Repeaters I can not set the ID of item as the Repeater control does not allow me to set the ID with Eval(datasource)
IDs are unique. All you need is this:
$("#CB_Selected").prop('checked', true);
Actually, you don't even need jQuery:
document.getElementByID('CB_Selected').checked = true;
As others have pointed out, it would be preferred to use a class rather than an ID if there are multiple checkboxes. In addition, an input cannot have children, so the closest function won't work; did you mean find (for children) or siblings?
Instead of giving several checkboxes the same ID -- which invalidates your html -- use a class on the checkboxes. Change:
<input id="CB_Selected" type="checkbox" name="ctl00$ContentPlaceHolder_Content_Wraper$ctl01$Repeater_Selected$ctl00$CB_Selected" />
To:
<input class="CB_Selected" type="checkbox" name="ctl00$ContentPlaceHolder_Content_Wraper$ctl01$Repeater_Selected$ctl00$CB_Selected" />
Then you can use the code:
$('#s_' + this.id).find(':checkbox.CB_Selected').prop('checked', true);