angular checkbox form with ng-repeat can only select one option - angularjs

I am trying to create a multistep form and step 2 is a bunch of checkboxes. Here is the form with checkboxes:
<form ng-submit="createSubCategory(formData)">
<div ng-repeat="sub_category in event_sub_categories">
<ion-checkbox ng-model="formData.sub_category" ng-true-value="'{{sub_category}}'">
{{sub_category}}</ion-checkbox>
</div>
<button type="submit" class="button button-block button-positive">Continue</button>
</form>
The data for the checkboxes (event_sub_categories) is pulled from a server. I need to save the inputs selected by the user to formData. formData is being collected on each page of the multistep form and it will be submitted with a post request after all of the form pages. I am new to angular and I am somewhat confused as to how check boxes work.
Question 1: I understand how ng-model works with normal textfields. But I'm not sure I get how it works with checkboxes. Does ng-model replace the html name element? Meaning, when I submit this to the server using $resource, are the keys of the data set by ng-model?
question 2: How can I name ng-model so that it is part of formData but so that it is also related to the name of sub_category being pulled from the database. The problem is that with the code above, only one checkbox can be selected at any given time and I want the user to be able to check many checkboxes at a given time. If it's not possible to do this, how can I get the functionality I need with checkboxes?

To be able to select multiple checkboxes at once you need an object (angular) to hold all of the values. I have implemented this code in my own applications and find it fairly easy for the function receiving it to interpret the object. (iterate the object checking for true/false values)
Here is your <ion-checkbox> code:
<ion-checkbox ng-repeat="sub_category in event_sub_categories" ng-model="formData[sub_category]">
This will set subcategory: true/false inside the formData object for every checkbox that is clicked.
Then all you need to do is send that formData object to where ever, the same way you were doing as before. Here is a codepen that displays the checkboxes changing, the updated formData object and the formData object stringified.
http://codepen.io/anon/pen/LNdaev?editors=1010
I have created my own values for event_sub_categories as an example, so of course these would be different from your own
Comment if you have any questions.

Related

Represent ng-model in a controller

I am developing application using AngularJS and ASP.Net MVC...
In my view, I have used ng-repeat=u in users in a div. Inside it, I set the ng-model in a textbox as ng-model=u.fName where fName is database field.
My question is, how I can represent the ng-model=u.fName in the angular controller??
For example, I tried to use $scope.n.fName but it doesn't work.
Note that u is only existing in ng-repeat block.
If you want to show/access to value changed by textbox outside of block, you should access via users again with another ng-repeat block:
<li ng-repeat="u in users">{{u.fName}}</li>
Or add ng-change="change(u)" to your textbox to get u anytime it's changed.
<input ng-model="u.fName" ng-change="change(u)" />
Plunkr example

Passing inputText value from inside a repeat

I've an object in salesforce and i want to make a form to enter values based on how many related list objects there are. Since i dont know how many related list objects there are i wanted to try and use a repeat on the page.
<apex:repeat value="{!prompts}" var="pmpt">
<div>
<label>{!pmpt.Name}</label>
<div>
<apex:inputText value="{!pmpt.DefaultValue__c}"/>
</div>
</div>
</apex:repeat>
So the code above gets the list of related list records (prompts) from the controller and displays a label and the inputText value assigned to it with the default value displayed. This works fine but i don't know how to read these values back in my controller when the user changes them from the default. Thanks.
The easiest way to do this is to assign to a variable in your Controller.. instead of
<apex:inputText value="{!pmpt.DefaultValue__c}"/>
it would be
<apex:inputText value="{!Your_Controller_Variable}"/>
This way when you submit the form the values in your input fields would be assigned to your variables in the controller and then you can perform any process you want with them
Now, since you have a repeat... and every input is related to a different record, what you can do is to change the inputText to inputField, then add a button submit the form on your page.. this will show the current values for each object field and.. will update the records on your list (the one you are using in the repeat). Have it like this:
<apex:inputField value="{!pmpt.DefaultValue__c}"/>
The inputField would assign the value to the corresponding record field on its own when you submit the form.

How to bind data depending on if checkbox is checked?

Just getting started on Angular, I'm using checkboxes to determine which parameters get sent during a get request (this is my attempt):
<input type="checkbox" ng-click="submit('color[]', 'red')"/>
<input type="checkbox" ng-click="submit('color[]', 'green')" checked/>
<input type="checkbox" ng-click="submit('color[]', 'blue')"/>
I have a variable $scope.params that stores the parameters of my http get request. My submit function is very simple:
$scope.submit = function (attribute, value) {
$scope.params[attribute] = value;
};
It simply adds color[] to the params object. Unlike radio, checkbox values can be stored as arrays and submitted as such: api?color[]=red&color[]=green as my backend is PHP this is the preferred format. However my submit function simply overwrites this every time. I'm not sure how to store multiple params with the same "key".
My other problem is that ng-click is not appropriate for this task as it doesn't take in the current state of the checkbox. Notice that my green checkbox is initially loaded as checked. Is there a way to bind this to my $scope.params object?
Ideally I want to implement something like:
$scope.params = {
"color[]" = ['red', 'green', 'blue']
};
According to Semicolon's answer below, I can use:
<input type="checkbox" ng-model="params.colors[]" ng-true-value="'red'"/>
<input type="checkbox" ng-model="params.colors[]" ng-true-value="'blue'"/>
<input type="checkbox" ng-model="params.colors[]" ng-true-value="'green'"/>
But naming anything with "[]" just breaks the code.
Checkboxes, like all input elements, are supported with ng-model. This core directive is a cousin of ng-bind. It says "the state of this element represents this model". Its behavior is determined by the input type. In the case of a checkbox, the value you are modeling is going to be boolean typically, since a checkbox is fundamentally a "boolean" input (checked/unchecked == true/false).
<input type="checkbox" ng-model="colors.red"/>
In the controller function:
$scope.colors = {
red: false,
green: true,
blue: false
};
Actually you can map checked/unchecked to non-boolean values too, using ng-true-value and ng-false-value. You can read more about these and other options for ng-model with checkboxes in the Angular docs:
https://docs.angularjs.org/api/ng/input/input%5Bcheckbox%5D
The core difference between ng-bind and ng-model is that the former is unidirectional (just a view) and the latter is bidirectional (the element can be used to change the model).
A more general answer regarding the premise of MVC in Angular:
In the example in your question, you were using a jQuery-like solution to try to achieve binding between the view and controller. This is really not ideal. Only bind a function to click events when you are specifically interested in having something take place "on click".
What if a user uses the tab key and the spacebar to check the box? The model would not get updated.
Or let's say you want to change the value in the model somewhere else -- maybe you have a "reset" button that returns them to the original values. The view would not get updated.
If the connection between the view and the model is all through "actions" it is easy for them to be out of sync. You'd have to make sure you handled every possible way the user could interact with the element and each time you change the data programmatically you would need to push the change to the view explicitly. But using ng-model and ng-bind lets you keep them synced no matter where the model is changed or how the user interacts. Really this is the main point of Angular.

angularjs multilingual text field with ngmodel

I'm trying to implement a multilingual text input field with a little dropdown button to the left for selecting the language. For instance, when the dropdown menu shows 'de' the text field should be bound to model.multilingualData['de'].someField and so on.
My first approach was to set ngModel to model.multilingualData[selectedLanguage].someField. But when the user selects a different language without filling in the field correctly, no error is set on the form, because the model now points to a different object.
My next idea was to create an entire element directive without ngModel, but then I wouldn't be able to do other validations like ngMaxLength.
I couldn't find anything helpful on the web either. Any idea on how to implement this properly?
EDIT
Here's a little fiddle that illustrates the problem: http://jsfiddle.net/FZ2kg/
Not only that the form appears valid when you switch languages, the previous field value is also deleted, because the model is set to null when the field becomes invalid.
would be nice if you use this awesome external directive for multilanguage!
https://angular-translate.github.io/
I hope it helps
If you need to have form validation for all language variations and you're loading all languages at once in your model, can't you just create an input per language in the form and hide all but the currently selected language?
Here's a fiddle: http://jsfiddle.net/jvl70/w3rstmwd/5/
<form name="myForm">
<div ng-repeat="(lang, value) in model.multilingualData"
ng-show="lang==stuff.currentLanguage">
<ng-form name="innerForm">
<div ng-class="{ 'has-error': innerForm.anything.$invalid }">
<input type="text" name="anything" ng-model="value.someField" ng-maxlength="6"/>
</div>
</ng-form>
</div>
</form>
(At first I tried to use dynamic names for each input but found that the individual field $invalid wasn't available for dynamically named inputs. See this post to get around it: Dynamic validation and name in a form with AngularJS.
As an alternative to ng-form, you could use dynamic names for each input and try one of the custom directives on the link.)
I guess if there were many possible languages, this approach might get slower but it's ok for a few languages.

Dynamic data-binding in AngularJS

I'm building an AngularJS app and I have ran into an issue. I have been playing with the framework for a while and I have yet to see documentation for something like this or any examples. I'm not sure which path to go down, Directive, Module, or something that I haven't heard of yet...
Problem:
Basically my app allows the user to add objects, we will say spans for this example, that have certain attribute's that are editable: height and an associated label. Rather than every span have its own dedicated input fields for height and label manipulation I would like to use one set of input fields that are able to control all iterations of our span object.
So my approx. working code is something like this:
<span ng-repeat="widget in chart.object">
<label>{{widget.label}}</label>
<span id="obj-js" class="obj" style="height:{{widget.amt}}px"></span>
</span>
<button ng-click="addObject()" class="add">ADD</button>
<input type="text" class="builder-input" ng-model="chart.object[0]['label']"/>
<input type="range" class="slider" ng-model="chart.object[0]['amt']"/>
The above code will let users add new objects, but the UI is obviously hardcoded to the first object in the array.
Desired Functionality:
When a user clicks on an object it updates the value of the input's ng-model to bind to the object clicked. So if "object_2" is clicked the input's ng-model updates to sync with the object_2's value. If the user clicks on "object_4" it updates the input's ng-model, you get the idea. Smart UI, essentially.
I've thought about writing a directive attribute called "sync" that could push the ng-model status to the bound UI. I've though about completely creating a new tag called <object> and construct these in the controller. And I've thought about using ng-click="someFn()" that updates the input fields. All of these are 'possibilities' that have their own pros and cons, but I thought before I either spin out on something or go down the wrong road I would ask the community.
Has anyone done this before (if so, examples)? If not, what would be the cleanest, AngularJS way to perform this? Cheers.
I don't think you need to use a custom directive specifically for this situation - although that may be helpful in your app once your controls are more involved.
Take as look at this possible solution, with a bit of formatting added:
http://jsfiddle.net/tLfYt/
I think the simplest way to solve this requires:
- Store 'selected' index in scope
- Bind ng-click to each repeated span, and use this to update the index.
From there, you can do exactly as you proposed: update the model on your inputs. This way of declarative thinking is something I love about Angular - your application can flow the way you would logically think about the problem.
In your controller:
$scope.selectedObjectIndex = null;
$scope.selectObject = function($index) {
$scope.selectedObjectIndex = $index;
}
In your ng-repeat:
<span ng-repeat="widget in chart.object" ng-click="selectObject($index)">
Your inputs:
<input type="text" class="builder-input" ng-model="chart.object[selectedObjectIndex]['label']"/>
<input type="range" class="slider" ng-model="chart.object[selectedObjectIndex]['amt']"/>

Resources