Angular: Send Checkbox Form Data to Firebase - angularjs

I have a object called list in my JS file:
$scope.list = {
hospital : 'Hospital',
clinic : 'Clinic',
gp : 'GP',
denist : 'Dentist',
aae : 'A&E'
};
I'm printing these five facilities to the form like so:
<form role="form" name="addPlaceForm" ng-submit="createHospital(newHospital)">
<label class="checkbox-inline" ng-repeat="(key, value) in list">
<input type="checkbox" id="{{ key }}" value="{{ key }}" ng-model="newHospital.facilities">{{ value }}
</label>
</form>
When I submit my form, I'd like it to send the the result of the checked checkboxes to my facilities object in Firebase. My createHospital function looks like this:
var rootRef = new Firebase('URL');
var placesRef = rootRef.child('places');
function createHospital(hospital) {
placesRef.push(hospital);
}
How can I push only the checked checkboxes to an nested object called facilities which sits inside my places object that's currently in my Firebase?
Any help with this is appreciated. Thanks in advance!

I made a plunker to demonstrate how to do this at http://plnkr.co/kfH4I5Fzy2Ma14FjQj67.
You were mostly right. The changes I made was making the ng-model="newHospital.facilities[key]" and initializing $scope.newHospital to {} so it is seen in the controller. I also added a submit button.
<form role="form" name="addPlaceForm" ng-submit="createHospital(newHospital)">
<label class="checkbox-inline" ng-repeat="(key, value) in list">
<input type="checkbox" id="{{ key }}" value="{{ key }}" ng-model="newHospital.facilities[key]">{{ value }}
</label>
</form>

Related

Angular setting form with scope?

What I want is a form that I can use for both creating and updating. So I pass before showing
$scope.form = {};
$scope.car = null;
$scope.getCar = function(hash) {
$http.get('/cars/'+hash).success(function(car) {
$scope.car = car;
$scope.form = car;
});
};
As you can see I add the result of the get to both car and form.
Now I'm opening the View:
<h1>{{ form.name }} <small>shows correctly</small></h1>
But a line after that I'm trying almost the same:
<form class="list" ng-submit="createOrUpdateForm(form)">
<label class="item">
<span class="input-label">Name</span>
<input type="text" ng-model="form.name">
Here it's not shown... But when I add the same line after it like this:
<input type="text" ng-model="car.name">
This does work, but then I can't use the ng-submit anymore, because that references to form.
Form some reason I can't set the form scope?
You should not manual assigning anything to form. A "form" is not the same as the data you manage using the form. Neither the empty object {} nor car make sense in that context.
Give the form a name, this will allow angular to assign it to a scope property.
<h1>{{ car.name }} <small>shows correctly</small></h1>
<form name="carForm" ng-submit="createOrUpdateForm(carForm)">
<label class="item">
<span class="input-label">Name</span>
<input type="text" ng-model="car.name">
$scope.createOrUpdateForm = function(form) {
if(form.$valid) {
console.log($scope.car.name);
// POST / PUT your data.
}
};

Checkbox not sending false value

I have a rails application which use AngularJS and I have a problem with a form, the problem is that I want to use a checkbox to send values true or false, but it only send true if it's checked and false if it's checked and unchecked after that, but if the user doesn't touch the checkbox, then it's not even sent as parameter.
<div class="checkbox">
<label>
<input type="checkbox" ng-model="car"> Do you have a car?
</label>
</div>
What can I do to make it send false if it the user doesn't ever check it?
Edit: The entire form is this, BTW, the form it's about creating a Poll, the car thing was just an example...
<h1>Create Poll</h1>
<form ng-submit="addPoll()" style="margin-top:30px;">
<div class="form-group">
<label>Title</label>
<input type="text" class="form-control" ng-model="title"></input>
</div>
<div class="form-group">
<label>Description</label>
<textarea type="text" class="form-control" ng-model="description"></textarea>
</div>
<br>
<div class="checkbox">
<label>
<input type="checkbox" ng-model="allow_anonymous_answer" ng-false-value="false"> Allow anonymous answers
</label>
</div>
<br>
<div class="form-group">
<label>Welcome message</label>
<textarea type="text" class="form-control" ng-model="initial_message"></textarea>
</div>
<div class="form-group">
<label>Outgoing Message</label>
<textarea type="text" class="form-control" ng-model="final_message"></textarea>
</div>
<button type="submit" class="btn btn-primary" style="float: right;">Continue</button>
</form>
When you hit Continue I make HTTP POST request with Restangular to create a Poll, but the problem is that when I don't touch the checkbox this is what I see in the log of Rails...
Started POST "/polls.json" for 127.0.0.1 at 2016-01-26 14:05:57 -0300
Processing by PollsController#create as JSON
Parameters: {"title"=>"asddddddddddddddda", "description"=>"aaaaaaaaaaaaaaaaaaaaa", "initial_message"=>"asdasdddddddddd", "final_message"=>"aaaaaaaaaaaaaaaaaaad", "poll"=>{"title"=>"asddddddddddddddda", "description"=>"aaaaaaaaaaaaaaaaaaaaa", "initial_message"=>"asdasdddddddddd", "final_message"=>"aaaaaaaaaaaaaaaaaaad"}}
Note that the parameter allow_anonymous_answer doesn't even appear, if I check the checkbox then I can see that the parameter is set as true, if I check it and then uncheck it, then it's set as false, but the problem is when the user doesn't even touch this, when this happens then the parameter is not even shown...
Just in case you wanna see, this is the controller of AngularJS...
angular.module('myapp').controller('CreatePollCtrl', ['$scope', 'Restangular',
function($scope, Restangular) {
Restangular.setFullResponse(true);
$scope.addPoll = function() {
var poll = {title: $scope.title, description: $scope.description, allow_anonymous_answer: $scope.allow_anonymous_answer, initial_message: $scope.initial_message, final_message: $scope.final_message};
Restangular.all('polls').post(poll).then(function(response) {
});
};
}]);
I think you should put a variable in your controller to achieve the binding between your HTML component and your JS code.
I am currently developing an Angular app, and what i do is to initialize all the ng-model variables in the first lines of my controller, so why dont you give a try to this:
In your first controllers lines:
$scope.allow_anonymous_answer = false;
Did you take a look at angular docs: https://docs.angularjs.org/api/ng/input/input[checkbox]
You can explicitly state what value the checkbox should send when it is not selected using ng-false-value
Add an ng-click to that checkbox and update the model there. Works fine.
<div class="checkbox">
<label>
<input type="checkbox" ng-model="car" ng-click="updateCar(this)">Do you have a car?</input>
</label>
</div>
In your controller:
var updateCar = function(checkbox) {
if (checkbox.checked) {
car = false;
}
else {
car = true;
}
}
I solved it...
In the controller
if ($scope.allow_anonymous_answer == null)
$scope.allow_anonymous_answer = false

Angular Empty option (Dynamic input)

Been searching all over Stackoverflow and there is loads of tips on how to remove the 'dreaded' empty (undefined) options element in a select dropdown. However I have yet to find an answer for when my code looks like this:
--VIEW--
<form class="simple-mods">
<fieldset ng-repeat="modifier in modifiers">
<label for="{{ modifier.id }}">{{ modifier.title }}</label>
<select name="" id="{{ modifier.id }}" ng-model="mods[modifier.id]" name="modifier[{{ modifier.id }}]" ng-mod="{{ modifier.title }}">
<option value="{{ variation.id }}" ng-repeat="variation in modifier.variations">{{ variation.title }}</option>
</select>
</fieldset>
<fieldset>
<button ng-click="addCart()" ng-if="!addStatus" class="btn btn-success" translate>Add to cart</button>
<button ng-if="addStatus" class="btn btn-warning" ng-bind-html="addStatus">{{ addStatus }}</button>
</fieldset>
</form>
-- CONTROLLER --
.controller('ProductCtrl', function ($scope, $rootScope, moltin, $timeout, product) {
var productId = product.id,
qty = 1,
mods = {};
$scope.product = product;
$scope.addStatus = null;
$scope.modifiers = product.modifiers;
});
If any one can help I would be very grateful.
#BETTY it doesnt seem to work. I have attached 2 screenshots
Screen shot 3
Screen shot 4 (Value is now a string)
#betty
<fieldset ng-repeat="modifier in modifiers" ng-init="mod[modifier.id] = modifier.variations[0].id">
<label for="{{ modifier.id }}">{{ modifier.title }}</label>
<select id="{{ modifier.id }}" ng-model="mods[modifier.id]" ng-options="variation.id as variation.title for variation in modifier.variations">
<option></option>
</select>
</fieldset>
Try to clean up modifier.variations in your controller, deleting undefined elements from modifier.variations
$scope.modifier.variations = $scope.modifier.variations.filter(function(n){ return n != undefined });
You need to inject $scope in your controller.
You need to set the ng-model right (=> mods[modifier.id]), either by using ng-init or setting it in the controller..
This solution uses ng-init which sets the default value to the first variation ID. I also removed everything you don't need and used ng-options (reduces some HTML ;)).
<fieldset ng-repeat="modifier in modifiers" ng-init="mods[modifier.id]=modifier.variations[0].id">
<label for="{{ modifier.id }}">{{ modifier.title }}</label>
<select id="{{ modifier.id }}" ng-model="mods[modifier.id]" ng-options="variation.id as variation.title for variation in modifier.variations">
<option></option>
</select>
</fieldset>
I also recommend adding an empty option-tag, here is why: ng-model is getting wrong value from dropdown
AND you need $scope.mods = {}; in the controller instead of var mods = {}; because you are using mods in the HTML!
Maybe you also need to use track by variation.id so that the selected value can be checked right (ng-model and option value). I answered a similar question and track by was the answer, see https://stackoverflow.com/a/32999399/595152 ;)

Angular form name is passed as string when passed as parameter

I'm simply trying to reset a form using the angular functions $setPristine & $setUntouched (several forms are created with ng-repeat).
I assign the form name dynamically by using the syntax {{ someName }} (the name is build on the server side and is passed as json (string)).
The name of the form is correctly assigned in the markup and validations are working as expected. The problem arrises when I pass that name as a parameter in the ng-click="reset(someName)" function.
When debugging the name comes as a string and not as the form object which causes the error. I did a quick test by hard-coding the name and pass that same name and it works fine.
My assumption is, the name coming from json is a string and the type is forwarded to the function as is, instead of the object.
So the question is: is there a way to convert that name so it is interpretated correctly by the controller. Or maybe there is something else I'm missing...
Here is the markup ( notice the name of the form uses {{ resto.contactForm }} ):
<form novalidate name="{{ resto.contactForm }}" ng-submit="submit(restoContact, resto.contactForm.$valid)" class="sky-form">
<div class="form-group">
<label class="checkbox state-success">
<input type="checkbox" ng-model="restoContact.sameAsUser" name="sameAsUser" id="sameAsUser" value="true" ng-click="contactAutoFill()"><i></i>Contact name is same as current user.
<input type="hidden" name="sameAsUser" value="false" />
</label>
</div>
<div class="form-group">
<label class="control-label" for="contactName">Contact Name</label>
<input type="text" ng-model="restoContact.contactName" name="contactName" id="contactName" placeholder="John, Doe" class="form-control" required />
<div ng-show="{{ resto.contactForm }}.contactName.$error.required && !{{ resto.contactForm }}.contactName.$pristine" class="note note-error">Please enter a name or check the box 'Same as current user'.</div>
</div>
<div class="form-group">
<label class="control-label" for="contactPhoneNumber">Contact Phone Number</label>
<input type="text" ng-model="restoContact.contactPhoneNumber" name="contactPhoneNumber" id="contactPhoneNumber" placeholder="+1 555-1234-567" class="form-control" required ng-pattern="phoneNumberPattern" />
<div ng-show="({{ resto.contactForm }}.contactPhoneNumber.$error.required || {{ resto.contactForm }}.contactPhoneNumber.$error.pattern) && !{{ resto.contactForm }}.contactPhoneNumber.$pristine" class="note note-error">Please enter a valid phone number.</div>
</div>
<div class="margin-leftM19">
<button class="btn btn-primary">Save Changes </button>
<button class="btn btn-default" ng-click="reset(resto.contactForm)">Cancel </button>
</div>
</form>
Here is the reset function in the controller (form comes as "contactForm1" which is the correct name but is a string and not the object):
$scope.reset = function (form) {
if (form) {
form.$setPristine();
form.$setUntouched();
}
//$scope.user = angular.copy($scope.master);
};
I have not implemented th submit method but I'm sure I will be running into the same issue.
Any suggestions or advices are welcome.
Thanks in advance...
Here is the fidle.js. the variable data is an exact response from the server.
[http://jsfiddle.net/bouchepat/v0mtbxep/]
SOLUTION:
http://jsfiddle.net/bouchepat/v0mtbxep/3/
I removed $setUntouched as it throws an error.
You can't dynamically name a <form> or <ng-form>.
Although what you want, is make the form usable in the controller. You could do the following:
// in controller
$scope.form = {};
$scope.reset = function() {
$scope.form.contact.$setPristine();
$scope.form.contact.$setUntouched();
};
// in html
<form name="form.contact">
This is happening because resto.contactForm is a string defined on the scope. The angular directive for form is just creating a variable on the scope with the same name. To get the variable by a string, use $eval. This should work:
$scope.reset = function (formName) {
var form = $scope.$eval(formName);
if (form) {
form.$setPristine();
form.$setUntouched();
}
//$scope.user = angular.copy($scope.master);
};

How to add object properties from ng-checked items to my ng-model object

I have four input fields which I'm using to add properties to a single object using ng-model= model.propertyName. I have a series of check boxes that I'm creating with ng-repeat that I could not figure out how to add unique propertyNames for each ng-model as they were created with the ng-repeat. As a work-around(or maybe this is correct, I'm not sure) I was able to write a function to add the checked items to an array. I was then trying to use a for-loop to iterate over the array and add each selected propertyName(string) to the ng-model object as a new property using a ng-click to call the function.
As-is when I click the "Add Technician" button I get the following error output:
TypeError: Cannot read property 'selection' of undefined
at Scope.$scope.addTechnician (..../scripts/controllers.js:
This occurs because $scope is undefined inside the conditional of my for loop in the addTechnician function. I can't understand why because when I pass $scope to the addTechnician function it recognizes the newTech inside the for loop. When I don't pass $scope to the addTechnician function it says newTech is undefined with the following error:
TypeError: Cannot set property 'cert1' of undefined
at Scope.$scope.addTechnician(.../scripts/controllers)
I'm pretty sure this has something to do with the way ng-repeat creates a new scope, which prototypically inherits from the parent scope. But again, I'm not sure.
Here is my controller
use strict';
angular.module('Carrepair2.controllers', [])
.controller('SetupCtrl', function($scope) {
$scope.certifications = [
{'name':'Engine Repair'},
{'name':'A/T & Transaxle'},
{'name':'Manual Drive Train & Axles'},
{'name':'Suspension & Steering'},
{'name':'Brakes'},
{'name':'Electrical & Electronic Systems'},
{'name':'Heating & Air Conditioning'},
{'name':'Engine Performance'},
{'name':'Light Vehicle Diesel Engines'}
];
// selected certifications
$scope.selection = [];
$scope.toggleCert = function(name) {
var idx = $scope.selection.indexOf(name);
//is currently selected
if (idx > -1) {
$scope.selection.splice(idx, 1);
}
//is newly selected
else{
$scope.selection.push(name);
}
};
$scope.addTechnician = function($scope) {
for(var i=0; i < $scope.selection.length - 1; i++){
$scope.newTech['cert' + (i + 1).toString()] = $scope.selection[i].name;
}
};
})
Here is my template
<form class="col-md-6">
<div class="input_wrapper">
<input type="text" name="first-name" ng-model="newTech.firstName" required>
<label for="first-name">First Name</label>
</div>
<div class="input_wrapper">
<input type="text" name="last-name" ng-model="newTech.lastName" required>
<label for="last-name">Last Name</label>
</div>
<div class="input_wrapper">
<input type="email" name="email" ng-model="newTech.email" required>
<label for="email">Email</label>
</div>
<div class="input_wrapper">
<input type="tel" name="phone" ng-model="newTech.phone" required>
<label for="phone">Phone</label>
</div>
<h5>Check all held ASE certifications</h5>
<ul class="list">
<li class="item item-checkbox" ng-repeat="certification in certifications">
<label class="checkbox">
<input type="checkbox" value="{{certification.name}}" ng-checked="selection.indexOf(certification.name) > -1" ng-click="toggleCert(certification)">
</label>
{{certification.name}}
</li>
</ul>
<button class="button button-block" ng-click="addTechnician()">Add Technician</button>
</form>
Ideally after the "Add Technician" button is clicked I want to end up with an object, my newTech ng-model object, that has the input field data and the properties from the checked items. Here is a jsFiddle with simplified code replicating the problem
http://jsfiddle.net/aq93z/7/
I solved it. I had to format my loop using angular.forEach(values, function(value, index){here is the jsFiddle with the solution http://jsfiddle.net/aq93z/9/. If you look at the $scope.newTech object created in the console the checkbox selections are added as properties of the newTech ng-model object.

Resources