React - Can't Uncheck Radio Button - javascript

I don't know what I'm doing wrong, but I'm unable to uncheck current radio button or select other radio buttons.
Basically, I have a table of occupants' details and I want to be able to indicate one of them as primary. The values are stored and retrieved in an mysql db. I am relatively new to ReactJS.
var PrimaryOccupantInput = React.createClass({
getInitialState: function()
{
return {
primary_occupant: (!(this.props.primary_occupant == null || this.props.primary_occupant == false))
};
},
primaryOccupantClicked: function()
{
this.setState({
primary_occupant: this.state.primary_occupant
});
this.props.primaryOccupantClicked(this.props.booking_occupant_id, this.state.primary_occupant.checked);
},
render: function() {
var is_primary = "";
if(this.state.primary_occupant != null)
{
if(this.state.primary_occupant == true)
{
is_primary = <span className="text-success">Yes</span>;
}
else if(this.state.primary_occupant == false)
{
is_primary = <span className="text-danger">No</span>;
}
else
{
is_primary = this.state.primary_occupant;
}
}
else
{
is_primary = <span className="text-muted"><em>undefined</em></span>;
}
return (
<div>
<input type="radio" id="primary_occupant" name="primary_occupant[]" ref="primaryOccupantCheckbox" checked={this.state.primary_occupant} onChange={this.primaryOccupantClicked} /> |
{is_primary}
</div>
);
}
});

onChange handler primaryOccupantClicked is basically a toggle function, so you want to set state opposite to current state (i.e. !this.state.primary_occupant). This will fix the issue:
primaryOccupantClicked: function()
{
this.setState({
primary_occupant: !this.state.primary_occupant
});
this.props.primaryOccupantClicked(this.props.booking_occupant_id, this.state.primary_occupant.checked);
},

Related

Knockout: Table Select Unselect Row. Issue/challenge with unselecting Row

I have a Table using Knockout to fill in data and to select the rows. The challenge right now is I can select the row and it's details I can see. But when I click on paging or if on any particular search box I wish to deselect the Row.
Here is the Fiddle which will explain More
Below is the Model Code for the HTML Page
var RowModel = function(id, name, status) {
this.ID = ko.observable(id);
this.Name = ko.observable(name);
this.Status = ko.observable(status);
};
RowModel.fromRawDataPoint = function(dataPoint) {
return new RowModel(dataPoint.id, dataPoint.name, dataPoint.status);
};
From the fiddle, I can see that you are implementing deselect by calling self.selected(null) and self.enableEdit(false).
So you can simply call these again whenever the page is changed or when a search is done.
self.deselect = function(){
self.selected(null);
self.enableEdit(false);
};
this.next = function() {
self.deselect();
if(self.pageNumber() < self.totalPages()) {
self.pageNumber(self.pageNumber() + 1);
}
}
this.lastpage = function() {
self.deselect();
if(self.pageNumber() < self.totalPages()) {
self.pageNumber(self.totalPages());
}
}
this.firstpage = function() {
self.deselect();
if(self.pageNumber() != 0) {
self.pageNumber(self.pageNumber()-self.pageNumber());
alert(self.pageNumber());
}
}
this.previous = function() {
self.deselect();
if(self.pageNumber() != 0) {
self.pageNumber(self.pageNumber() - 1);
}
}
Edit: After your comment about the ID, Name and Status not getting updated, I added 3 new observables selectedName, selectedID and selectedStatus. I am using these observables in HTML so that they can be updated whenever selected is changed. This is done by using a subscribe function on selected.
HTML
<input type="text" name="ID" data-bind="value: selectedID, enable: enableEdit" />
<br>Name :
<input type="text" name="Name" data-bind="value: selectedName, enable: enableEdit" />
<br>Status :
<input type="text" name="Status" data-bind="value: selectedStatus, enable: enableEdit" />
JS
self.selected = ko.observable(self.items()[0]);
self.selectedID=ko.observable(self.items()[0].ID());
self.selectedName=ko.observable(self.items()[0].Name());
self.selectedStatus=ko.observable(self.items()[0].Status());
self.selected.subscribe(function(newValue){
if (newValue === null){
self.selectedID(null);
self.selectedName(null);
self.selectedStatus(null);
return;
}
if (typeof newValue !== 'undefined'){
self.selectedID(newValue.ID());
self.selectedName(newValue.Name());
self.selectedStatus(newValue.Status());
}
});

Validating different types of form inputs with criterias

I want to get the answers to a form upon submission and parse them to JSON.
This works quite good but I want some validation before sending the data.
I tried a lot of variations of the snippet down below but am still stuck.
Steps:
Prevent default event on "send"
Get Form
Iterate through the elements of the form
Eliminate empty items and their value
If checkbox is checked: value = true
Store correct items in data
Return data
Somehow I can't get to work steps 4 and 5 work at the same time, every time I get one of them to work I screw over the other one.
In this snippet, the checkbox works as intented but the textfield doesn't:
If anybody can point me in the right direction with the if/else statements or something like that it would be greatly appreciated.
document.addEventListener('DOMContentLoaded', function(){
var data = {};
var formToJSON = function formToJSON(form) {
var data = {};
for (var i = 0; i < form.length; i++) {
var item = form[i];
//looking for checkbox
if (item.value =="") {
continue;
}
else {
if (item.checked == false) {
data[item.name] = false;
}
else {
data[item.name] = item.value;
}
}
}
return data; };
var dataContainer = document.getElementsByClassName('results__display')[0];
form = document.getElementById('formular').querySelectorAll('input,select,textarea');
butt = document.getElementById('knopfabsenden');
butt.addEventListener('click', function (event) {
event.preventDefault();
handleFormSubmit(form = form);
});
var handleFormSubmit = function handleFormSubmit(event) {
var data = formToJSON(form);
dataContainer.textContent = JSON.stringify(data, null, " ");
}
}, false);
<div id="formular">
<label class="formular__label" for="machineName">Textfield Test</label>
<input class="formular__input formular__input--text" id="machineNumber" name="machineNumber" type="text"/>
<br>
<input class="formular__input formular__input--checkbox" id="checkTest" name="checkTest" type="checkbox" value="true"/>
<label class="formular__label formular__label--checkbox" for="checkTest">Checkbox Test</label>
<br>
<button class="formular__button" id="knopfabsenden" type="submit">Submit</button>
</div>
<div class="results">
<h2 class="results__heading">Form Data</h2>
<pre class="results__display-wrapper"><code class="results__display"></code></pre>
</div>
The problem is .checked will always be false if it doesn't exist. So the text field gets the value false.
for (var i = 0; i < form.length; i++) {
var item = form[i];
//looking for checkbox
if (item.value ==="") {
continue;
}
else {
if (item.type === "text") {
data[item.name] = item.value;
}
else if (item.type === "checkbox"){
data[item.name] = item.checked;
}
}
}
In this code snippet I check the type of the input and handle it accordingly. also notice I use the === operator and not the == operator as a best practice (Difference between == and === in JavaScript)

Unable to set default input radio checked if used with v-for

I am trying to add radio buttons to my code. Everything works fine except one thing. When I am using v-for loop for creating radios, the default radio is not getting checked. It works if, I put it outside the for loop.
I have tried this :-
:checked="index == 1"
and this ( as suggested in some answers ):-
:checked="{ index == 1 }"
But none of them is working for me.
Below is my template snippet:-
<div class="props-data">
<!-- <input type="radio" :checked="currentStep==1"> -->
<span v-for="(shape, index) in availableShapes" v-if="currentStep==1">
<div>
<input type="radio" :id="shape" :value="shape" v-model="selectedShape" :checked="index == 1">
<label :for="shape">{{shape}}</label>
</div>
</span>
</div>
Note:- steps-container is the main parent class where Vue instance is being created.
Below is my js code:-
window.onload = function(){
new Vue({
el: '#steps-container',
data: function() {
return {
currentStep: 1,
availableShapes: ['Rectangle','Circle','Square','Ellipse'],
selectedShape: undefined
};
},
methods: {
cancel: function(){
this.currentStep = 1;
jQuery('#main-action').text('Go to step '+ (this.currentStep+1));
},
nextStep: function(){
if( this.currentStep == 2 ){
jQuery('#main-action').text('Startover');
this.currentStep++;
}
else{
if( this.currentStep == 3 ){
this.currentStep = 1;
}
else{
this.currentStep++;
}
jQuery('#main-action').text('Go to step '+ (this.currentStep+1));
}
}
},
mounted: function(){
},
updated: function(){
}
});
}
Any help would be much appreciated.
You won't need to set the checked attr yourself. By using v-model="selectedShape" you have linked all the radio input with selectedShape.
You can already control the checked attr by controlling the value of selectedShape.
So set the initial value of selectedShape to the default value, and it will be checked by default.
<input type="radio" :id="shape" :value="shape" v-model="selectedShape"> (remove :checked="index == 1")
data: function() {
return {
//...
selectedShape: "THE DEFAULT VALUE"
};
},

Javascript validation - group validation - if one entered, then all required

Using just jQuery (not validation plugin) I have devised a way to do a "if one, then all" requirement, but it's not at all elegant.
I'm wondering if someone can come up with a more elegant solution? This one uses some loop nesting and I'm really not pleased with it.
if ($("[data-group]")) {
//Store a simple array of objects, each representing one group.
var groups = [];
$("[data-group]").each(function () {
//This function removes an '*' that is placed before the field to validate
removeCurError($(this));
var groupName = $(this).attr('data-group');
//If this group is already in the array, don't add it again
var exists = false;
groups.forEach(function (group) {
if (group.name === groupName)
exists = true;
});
if (!exists) {
var groupElements = $("[data-group='" + groupName + "']");
var group = {
name: groupName,
elements: groupElements,
trigger: false
}
group.elements.each(function () {
if (!group.trigger) {
group.trigger = $(this).val().length !== 0;
}
});
groups.push(group);
}
});
//Now apply the validation and alert the user
groups.forEach(function (group) {
if (group.trigger) {
group.elements.each(function () {
//Make sure it's not the one that's already been filled out
if ($(this).val().length === 0)
// This function adds an '*' to field and puts it into a
// a sting that can be alerted
appendError($(this));
});
}
});
You don't have to store the groups in an array, just call the validateGroups function whenever you want to validate the $elements. Here is a working example http://jsfiddle.net/BBcvk/2/.
HTML
<h2>Group 1</h2>
<div>
<input data-group="group-1" />
</div>
<div>
<input data-group="group-1" />
</div>
<h2>Group 2</h2>
<div>
<input data-group="group-2" value="not empty" />
</div>
<div>
<input data-group="group-2" />
</div>
<div>
<input data-group="group-2" />
</div>
<button>Validate</button>
Javascript
function validateGroups($elements) {
$elements.removeClass('validated');
$elements.each(function() {
// Return if the current element has already been validated.
var $element = $(this);
if ($element.hasClass('validated')) {
return;
}
// Get all elements in the same group.
var groupName = $element.attr('data-group');
var $groupElements = $('[data-group=' + groupName + ']');
var hasOne = false;
// Check to see if any of the elements in the group is not empty.
$groupElements.each(function() {
if ($(this).val().length > 0) {
hasOne = true;
return false;
}
});
// Add an error to each empty element if the group
// has a non-empty element, otherwise remove the error.
$groupElements.each(function() {
var $groupElement = $(this);
if (hasOne && $groupElement.val().length < 1) {
appendError($groupElement);
} else {
removeCurError($groupElement);
}
$groupElement.addClass('validated');
});
});
}
function appendError($element) {
if ($element.next('span.error').length > 0) {
return;
}
$element.after('<span class="error">*</span>');
}
function removeCurError($element) {
$element.next().remove();
}
$(document).ready(function() {
$('button').on('click', function() {
validateGroups($("[data-group]"));
});
});
You might get some milage out of this solution. Basically, simplify and test your solution on submit click before sending the form (which this doesn't do). In this case, I simply test value of the first checkbox for truth, and then alert or check the required boxes. These can be anything you like. Good luck.
http://jsfiddle.net/YD6nW/1/
<form>
<input type="button" onclick="return checkTest()" value="test"/>
</form>
and with jquery:
checkTest = function(){
var isChecked = $('input')[0].checked;
if(isChecked){
alert('form is ready: input 0 is: '+isChecked);
}else{
$('input')[1].checked = true;
$('input')[2].checked = true;
}
};
//create a bunch of checkboxes
$('<input/>', {
type: 'checkbox',
html: 'tick'
}).prependTo('form');
$('<input/>', {
type: 'checkbox',
html: 'tick'
}).prependTo('form');
$('<input/>', {
type: 'checkbox',
html: 'tick'
}).prependTo('form');

Angular - How to make results show, only if unchecked

I have code that filters and shows the result of the box checked. When all the checkboxes are unchecked it shows all the results and when boxes are checked it only shows the boxes selected.
However, I'm trying to show all the results when the boxes are unchecked and if a check box is checked then it doesn't show that specific result, while continuing to show the boxes that are unchecked.
controller.js
function AdvisorListCtrl( $location, $scope, db) {
$scope.orderProp = 'number';
$scope.courseCheckboxes = {};
$scope.teacherCheckboxes = {};
$scope.courses = db.courses.query({order:$scope.orderProp, name:$scope.query});
function getChecked(obj){
var checked = [];
for(var key in obj)
if(obj[key]) checked.push(key);
return checked;
}
$scope.searchFilter = function(row){
var courChecked = getChecked($scope.courseCheckboxes);
var teachChecked = getChecked($scope.teacherCheckboxes);
if (courChecked.length == 0 && teachChecked.length == 0)
return true;
else {
if ($scope.courseCheckboxes[row.name])
return true;
else {
return row.teacher.split(/,\s*/).some(function(teach){
return $scope.teacherCheckboxes[teach];
});
}
}
}
}
html
<li><b><h2>Filter by Class</h2></b></li>
<li ng-repeat="course in courses | orderBy:['-status', 'name']">
<label>
<input type="checkbox" ng-model="courseCheckboxes[course.name]" />{{course.name}}
</label>
</li>
I had misunderstood your question so I re-edited the answer.
When searchFilter(record) returns false the record is filtered out (and not displayed).
Here is a version of the filter that should do the opposite of what was doing (hide the checked merchants, and the merchants containing the checked brands). Hope this helps.
html
<div ng-repeat="record in records | filter: searchFilter">
{{record.Description}}
js
$scope.searchFilter = function(row){
var mercChecked = getChecked($scope.merchantCheckboxes);
var brandChecked = getChecked($scope.brandCheckboxes);
if(mercChecked.length == 0 && brandChecked.length == 0)
return true;
else{
if($scope.merchantCheckboxes[row.MerchantName]){
return false; // <----------------- changed here true to false
} else {
// changed here adding !
return !row.BrandList.split(/,\s*/).some(function(brand){
return $scope.brandCheckboxes[brand];
});
}
}
};

Categories

Resources