Angular: Binding objects to <select> - javascript

Firstly, I should say that I have only attacked Angular.js for 2 days now so I may be approaching this whole thing wrong.
My example "Person" object (or model if I understand) has two properties, Firstname and Title. I have two fields <select> for title and <input type="text" /> for name. The Firstname binding works fine and I am happy, but the title is confusing me.
I am binding an object array with Code and Desc which populates fine. But when I want to get (on submit) or set (on load) it does not work because the binding uses the entire title object.
http://jsfiddle.net/qm7E7/11/
(Click on Next to display the serialized object.)
HTML
<div ng-app ng-controller="PersonCtrl">
<form name="myForm" ng-submit="submit()">
Title: <select ng-model="Person.Title" ng-options="t.Desc for t in TitleList">
<option style="display: none" value="">Please select</option>
</select>
<br/>
Firstname: <input type="text" ng-model="Person.Firstname" />
<br/>
<input type="submit" value="Next" />
<br/>
<div id="obj"></div>
</form>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js">
JS
// Person controller
function PersonCtrl($scope) {
$scope.TitleList = [{Code: 'MR', Desc: 'Mr'},
{Code: 'MRS', Desc: 'Mrs'}]
$scope.Person = {
Firstname: 'dave',
Title: 'MR'
};
$scope.submit = function () {
$("#obj").text(JSON.stringify($scope.Person));
};
}
Am I misunderstanding the whole concept or what. I should also say that I don't want to use the whole MVC routing concept. Just the objects and "2 way binding".

The select input is a very special puppy in angular.
Here's an updated fiddle:
http://jsfiddle.net/qm7E7/16/
You could provide the data as an object, where the keys are the codes and the values are the description:
$scope.TitleList = {
'MR' : 'Mr',
'MRS' : 'Mrs'
};
And in your html:
<select ng-model="Person.Title" ng-options="code as desc for (code, desc) in TitleList">
the syntax is a little tricky. You can read more about it in the angular docs, especially the comments. http://docs.angularjs.org/api/ng.directive:select

You need to specify the value
<select ng-model="Person.Title" ng-options="t.Code as t.Desc for t in TitleList">
http://jsfiddle.net/qm7E7/19/

Related

ReactJS and Meteor: Generating <select> options?

I'm using React and Meteor to generate a table of information about items in a catalog. I also made a form so that users can add new items. Each item has a name, price and manufacturer. This works perfectly fine when I make all the inputs text areas, but I want to make the manufacturer input a with tags generated according to a Meteor collection called Manufacturers.
Form = React.createClass({
propTypes: {
manufacturer: React.PropTypes.object.isRequired
},
renderOptions(){
return(<option value={this.props.manufacturer.name}>{this.props.manufacturer.name}</option>);
},
submitItem(event){
event.preventDefault();
var name=React.findDOMNode(this.refs.nameInput).value.trim();
var price=React.findDOMNode(this.refs.priceInput).value.trim();
var manufacturer=React.findDOMNode(this.refs.manufacturerInput).value.trim();
Items.insert({
name: name,
price: price,
manufacturer: manufacturer,
});
React.findDOMNode(this.refs.nameInput).value="";
React.findDOMNode(this.refs.priceInput).value="";
},
render(){
return(
<footer>
<form className="new-item" onSubmit={this.submitItem}>
<input type="text" ref="nameInput" placeholder="Name" required />
<input type="text" ref="priceInput" placeholder="Price" required />
<button onClick={this.submitItem}>ADD</button>
</form>
<select ref="manufacturerInput" defaultValue="" required />
<option value="" disabled>Manufacturer</option>
{this.renderOptions()}
</select>
</footer>
);
}
});
How do I make this work? I've been pulling my hair out all day trying to figure it out, but Meteor just keeps telling me "Expected corresponding JSX closing tag for (38:8)". What am I doing wrong here? It works just fine when they're all but this destroys my entire app.
You accidentally closed your select element here:
<select ref="manufacturerInput" defaultValue="" required />
Remove the /.

How to retrieve in a .js function the target value of a form which comes from an other template?

Hello I'm new on meteor and I would like to retrieve the value of a form in a template thanks to an Event in my .js file.
It worked when I was using a simple value in my select menu : I retrieved the value of my form with help an Event and I sent it in a Function.
But now, I am using a template which gives (with #for each) all the values disponible in my collection to supply my select options with all the existant elements.
The problem is I don't succeed to retrieve the value selected in my form from the client.
Thank you for your help.
Here is a part of my code :
<template name="searchBar">
<div class="searchBar">
<form class="form-inline">
<select name="make">
{{#each makes}}
{{>make}}
{{/each}}
</select>
<select name="model">
{{#each cars}}
{{>model}}
{{/each}}
</select>
<input type="text" name="price" placeholder="Prix maximum"/>
<input type="text" name="quickSearch" placeholder="Mots-clés" />
<button class="btn btn-primary btn-info" type="submit" value="Rechercher">Rechercher</button>
</form>
</div>
</template>
<template name="make">
<option>{{make}}</option>
</template>
Template.searchBar.events({
"submit form": function (event) {
var make = event.target.make.value;
var model = event.target.model.value;
var price = event.target.price.value;
var quickSearch = event.target.quickSearch.value;
Meteor.call("findCar", make, model, price, quickSearch);
return false;
}
});
findCar: function (quickSearch,make,model,price) {
console.log("fonction called");
console.log("make"); // It send : make instead of the real make
var carsFound = Cars.find({make:make, model:model, price:price}).fetch();
console.log(carsFound);
}
Rather than use the passed in event object, I sometimes find it is easier to use jQuery (which is natively used in Meteor) selector's to find input values.
If you added an id to your select:
<select name="make" id="make">
{{#each makes}}
{{>make}}
{{/each}}
</select>
You can access it in your event as such:
$("#make").val();
Tip: If you want to avoid jQuery and use the built in DOM objects, I find it really helpful to use the debugger in Firefox or Chrome. They allow you to inspect the object properties in detail.

How to dynamically create multiple form input fields with incremented ng-models?

After reading this article, I understand how to dynamically add a form field using ng-repeat.
I am wondering how can multiple form elements be dynamically created with incrementing ng-model values.
For example, the following would be created from a button click.
<input ng-model="vm.foo.bar1.first">
<input ng-model="vm.foo.bar1.second">
<input ng-model="vm.foo.bar1.third">
<input ng-model="vm.foo.bar1.fourth">
<input ng-model="vm.foo.bar2.first">
<input ng-model="vm.foo.bar2.second">
<input ng-model="vm.foo.bar2.third">
<input ng-model="vm.foo.bar2.fourth">
<input ng-model="vm.foo.bar3.first">
<input ng-model="vm.foo.bar3.second">
<input ng-model="vm.foo.bar3.third">
<input ng-model="vm.foo.bar3.fourth">
How can this be done?
I would suggest to restructure your ViewModel to make vm.foo.bar an array. Then this would be trivial:
<div ng-repeat="item in barItems">
<input ng-model="vm.foo.bar[$index].first">
<input ng-model="vm.foo.bar[$index].second">
<input ng-model="vm.foo.bar[$index].third">
<input ng-model="vm.foo.bar[$index].fourth">
</div>
Or, if you insist, then also
<div ng-repeat="item in barItems" ng-init="outerIdx = $index">
<input ng-repeat='p in ["first", "second", "third", "fourth"]'
ng-model="vm.foo.bar[outerIdx][p]">
</div>
(I'm assuming here, that unlike with first, second, etc..., the number of bars is not known - hence an array is a better option)
EDIT:
If you really want, you could also make vm.foo an object that holds properties bar1, bar2, etc...:
<div ng-repeat="item in [1, 2, 3, 4]">
<input ng-model="vm.foo['bar' + item].first">
<input ng-model="vm.foo['bar' + item].second">
<input ng-model="vm.foo['bar' + item].third">
<input ng-model="vm.foo['bar' + item].fourth">
</div>
but don't forget to first create vm.foo object in the controller:
this.foo = {};
When I have to do this I use the $index to control the names of things. Although I've never tried this exact code, this should work.
<input ng-model='vm.foo.bar3[$index]'></input>
$index comes along whenever you do ng-repeat and is just the index of the list item. So that should end up making ng-models that are vm.foo.bar3.0 to whatever.
To my point of view, you should create arrays of models in your controller.
$scope.vm.foo = [{
bar1: [{
first: '',
second: '',
...
},
bar2: ...
],
}]
And then in your view iterate on your tab :
<div ng-repeat="elem in foo">
<div ng-repeat="input in elem">
<input ng-model="input">
</div>
</div>
Hope it will help you !

Reuse HTML but bind different model

I'm using AngularJS in my website. One page on my site is quite large, as in, it has a lot of HTML elements. Imagine something like this:
<div id="bronze">
<input ng-model="league.bronze.name">
<input ng-model="league.bronze.title">
<input ng-model="league.bronze.description">
... about 15 more inputs ...
<input ng-model="league.bronze.color1">
<input ng-model="league.bronze.color2">
</div>
<div id="silver">
<input ng-model="league.silver.name">
<input ng-model="league.silver.title">
<input ng-model="league.silver.description">
... about 15 more inputs ...
<input ng-model="league.silver.color1">
<input ng-model="league.silver.color2">
</div>
I also have gold and platinum. A site admin must fill in all these settings. This is not a problem for him. But it is for me as a developer.
Everytime I add one or more elements to the "bronze" section then I also have to do the same for every other section. The only difference is the ng-model value.
Isn't there a smarter way to do this? Because right now I'm kinda repeating my self everytime an element needs to be added...
In your controller do:
$scope.types = ['gold', 'silver', 'bronze'];
$scope.properties = ['name', 'title', 'description'];
And in your html do this:
<div ng-repeat="myType in types" id="{{myType}}">
<input ng-repeat="myProperty in properties" ng-model="league[myType][myProperty]">
</div>
EXAMPLE
Check out this quick example of using ng-repeat for input fields
plunker
in your case it will be something like:
<div ng-repeat="league in leagues>
<input ng-model="league.bronze.name">
<input ng-model="league.title">
<input ng-model="league.description">
... about 15 more inputs ...
<input ng-model="league.color1">
<input ng-model="league.color2">
</div>

Angular Changing filter based on select value and text input

I am new to Angular so I think this is a basic concept that I'm just missing some step on. I want to have a search that does basic angular filtering, but I want to have a separate select that chooses what the text input searches on. Currently it looks like this:
Search inputs:
<input type="text" class="form-control" id="search-users" ng-model="userQuery">
<span class="input-group-btn">
<select ng-model="searchOn" ng-change="setSearchOn(searchOn)">
<option value="CustomerId" selected>CustomerId</option>
<option value="Username">Username</option>
</select>
</span>
Function:
$scope.setSearchOn = function(searchOnIn){
console.log("setting searchOn to "+searchOnIn);
$scope.searchOn = searchOnIn;
}
Repeater:
<div ng-repeat="user in users | filter:userQuery.searchOn">
I feel like i shouldn't even need the function, shouldn't i be able to data-bind the value of the select to the filter on the repeater? I couldn't get that to work either. Help would be appreciated. Angular is awesome, but the beginning learning the way it works is a little rough :)
As I understand it, we want to pick the property which we search on with the dropdown, and then search that property for value on the userQuery input.
One way to accomplish that is to (re)build an object to filter with when either userQuery or searchOn alters.
var app = angular.module('myapp', []).controller('ctrl', function($scope){
/* some test data */
$scope.users = [{CustomerId : 1, Username : 'Pete'},
{CustomerId : 2, Username : 'John'},
{CustomerId : 3, Username : 'Claus'}]
$scope.setSearchFilter = function()
{
$scope.searchFilter = {};
$scope.searchFilter[$scope.searchOn] = $scope.userQuery;
}
})
In the html, I've set an ng-change on both the userQuery and searchOn to update the search filter.
<div ng-controller="ctrl">
<input type="text" class="form-control" id="search-users" ng-model="userQuery" ng-change="setSearchFilter()" />
<span class="input-group-btn">
<select ng-model="searchOn" ng-change="setSearchFilter()">
<option value="CustomerId" selected>CustomerId</option>
<option value="Username">Username</option>
</select>
</span>
<div ng-repeat="user in users | filter:searchFilter">
{{user.CustomerId}} -- {{user.Username}}
</div>
</div>
http://jsfiddle.net/nwdx7/1/

Categories

Resources