I am using Angularjs and I have a dropdown box that lists several items. If the item the user needs is not in the list I need to allow the user to enter the data. Is this possible? How would I do it?
Try this out
Working Demo
html
<div ng-app="myapp">
<fieldset ng-controller="FirstCtrl">
<select ng-options="p.name for p in people" ng-model="selectedPerson"></select>
<br>
Name:<input type="text" ng-model="name"/>
<button ng-click="add(name)">Add</button>
</fieldset>
</div>
script
var myapp = angular.module('myapp', []);
myapp.controller('FirstCtrl', function ($scope) {
$scope.people = [{
name: 'John'
}, {
name: 'Rocky'
}, {
name: 'John'
}, {
name: 'Ben'
}];
$scope.add = function(value)
{
var obj= {};
obj.name = value;
$scope.people.push(obj);
$scope.name = '';
}
});
You seem to want something like a tagging widget. Maybe looking at angular-tags you can accomplish what you want
Related
I have an array of objects. I displayed the names in input fields. Now I want the updated object (whatever user fills in input field) on button click
Example if I enter “abcde” and “pq” in input field it should show update object on button click
[
{
name:'abcde’
},
{
name:'pq'
}
];
http://plnkr.co/edit/51BlTe5tAEgMV7ZlJLKV
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.c = [
{
name:'abc'
},
{
name:'pqr'
}
];
$scope.onclick =function(){
alert('dd')
console.log($scope.c)
}
});
Use ng-model in your template
<li ng-repeat="x in c">
<input type="text" ng-model='x.name' value="{{x.name==='abc'?'ddd':'hhh'}}"/>
</li>
If you need to update $scope.c on button click, use ng-model on a different scope variable and assign the same to $scope.c in onclick
UPDATE:
Also note that ng-model does not depend on value, so x.name==='abc'?'ddd':'hhh' should be done in the onclick or ng-change event handler
You can also try this out.
<li ng-repeat="x in displayValue">
<input type="text" ng-model='x.name' ng-change='valueChanged(x.name,$index)'/>
</li>
And in your controller you can have 2 different json one is for display purpose and one for actual values. So conditionally showing "hhhh" and "dddd" will also be satisfy.
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.displayValue = [
{
name:'abc' == 'abc'? 'hhhh' : 'dddd'
},
{
name:'pqr' == 'abc'? 'hhhh' : 'dddd'
}
];
$scope.actualValue = [
{
name: ''
},
{
name:''
}
];
$scope.valueChanged =function(value,index)
{
$scope.actualValue[index].name = value;
}
$scope.onclick =function(){
console.log($scope.actualValue)
}
});
I am trying to create a list of editable inputs from a list of items. I want the user to be able to edit any of the items, but if they change there mind they can click a button and reset it back to the way it was.
So far I have everything working except the reset.
my html
<div ng-app ng-controller="TestController">
<div ng-repeat="item in list">
<label>Input {{$index+1}}:</label>
<input ng-model="item.value" type="text" ng-click="copy(item)"/>
<button ng-click="reset(item)">
x
</button>
</div>
{{list}}<br>
{{selected_item_backup}}
</div>
my controller
function TestController($scope) {
$scope.selected_item_backup = {};
$scope.list = [ { value: 'value 1' }, { value: 'value 2' }, { value: 'value 3' } ];
$scope.reset = function (item) {
// i know this wont work for many reasons, it is just an example of what I would like to do
item = $scope.selected_item_backup;
};
$scope.copy = function (item) {
angular.copy(item, $scope.selected_item_backup);
};
}
and here is a fiddle
http://jsfiddle.net/ryanmc/1ab24o4t/1/
Keep in mind that this is a simplified version of my real code. My objects will have many editable fields each. Also they are not indexed, and so the index cannot be relied on. I just want to be able to assign the original item on top of the new and have it replaced.
This is work solution jsfiddle
function TestController($scope) {
$scope.list = [{
value: 'value 1'
}, {
value: 'value 2'
}, {
value: 'value 3'
}];
var orgiinalList = [];
angular.forEach($scope.list, function(item) {
orgiinalList.push(angular.copy(item));
});
$scope.reset = function(index) {
$scope.list[index] = angular.copy(orgiinalList[index]);
};
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app ng-controller="TestController">
<div ng-repeat="item in list">
<label>Input {{$index+1}}:</label>
<input ng-model="item.value" type="text" />
<button ng-click="reset($index)">
x
</button>
</div>
{{list}}
<br>
</div>
Changing your reset function so that it looks like this:
$scope.reset = function(index) {
$scope.list[index].value = "value "+ (index+1);
};
will make it so that your 'reset' buttons restore what would be those original values...
Angular controller:
function TestController($scope) {
$scope.selected_item_backup = {};
$scope.list = [{
value: 'value 1'
}, {
value: 'value 2'
}, {
value: 'value 3'
}];
$scope.reset = function(index) {
$scope.list[index].value = "value " + (index+1);
};
$scope.copy = function(item) {
angular.copy(item, $scope.selected_item_backup);
};
}
HTML:
<div ng-app ng-controller="TestController">
<div ng-repeat="item in list">
<label>Input {{$index+1}}:</label>
<input ng-model="item.value" type="text" ng-click="copy(item)" />
<button ng-click="reset($index)">
x
</button>
</div>
</div>
The values of your array are directly modeled by those inputs - therefore as a user types changes into those inputs they are directly manipulating the $scope.list array so you cant really use it as a reference... Hope that makes sense.
You can't use global functions as controllers in newer versions of angular but you can register your controllers in your application:
<div ng-app ng-controller="TestController">
<div ng-repeat="item in list">
<label>Input {{$index+1}}:</label>
<input ng-model="item.value" type="text" ng-click="copy($index,item)"/>
<button ng-click="reset($index,item)">
x
</button>
</div>
{{list}}<br>
{{selected_item_backup}}
function TestController($scope) {
$scope.selected_item_backup = [];
$scope.list = [ { value: 'value 1' }, { value: 'value 2' }, { value: 'value 3' } ];
$scope.reset = function (index) {
$scope.list[index].value = $scope.selected_item_backup[index];
};
$scope.copy = function (index,item) {
// backup the old value
$scope.selected_item_backup[index] = item.value;
};
}
Here's a simple controller that contains a list of users:
<script type="text/javascript">
angular.module('project', [])
.controller('UsersController', ['$scope', function ($scope) {
$scope.users = [
{ text: 'User 1', done: true, extension: 123 },
{ text: 'Another user', done: false, extension: 456 }];
}]);
$scope.selectedUsers = function () {
var results = [];
for (i = 0; i < $scope.users.length; i++) {
if ($scope.users[i].done) {
results.push($scope.users[i]);
}
}
return results;
};
</script>
And a simple HTML that just shows a checkbox for each user, and a message to select something if no user is selected.
<div ng-app="project" ng-controller="UsersController">
<input type="checkbox" ng-repeat="user in users" ng-model="user.done" id="selectUser{{$index}}" />
<div ng-hide="selectedUsers().length">Select something</div>
</div>
The code works, but it looks kind of ugly.
Is there a less procedural way of getting to the same result?
You can simply filter down the set of users based on the done property and check the length of it.
<div ng-hide="(users | filter:{done:true}).length">Select something</div>
angular.module('project', [])
.controller('UsersController', ['$scope', function ($scope) {
$scope.users = [
{ text: 'User 1', done: true, extension: 123 },
{ text: 'Another user', done: false, extension: 456 }];
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="project" ng-controller="UsersController">
<input type="checkbox" ng-repeat="user in users" ng-model="user.done" id="selectUser{{$index}}" />
<div ng-hide="(users | filter:{done:true}).length">Select something</div>
</div>
The way you have it implemented is rather inefficient as the selectedUsers function, which iterates over all users, runs on every digest. It might be acceptable if you a small number of users.
For completeness sake, however, another approach would be to calculate the number of user.done === true and keep track of the count (rather than re-count):
$scope.users = [
{ text: 'User 1', done: true, extension: 123 },
{ text: 'Another user', done: false, extension: 456 }];
$scope.selection = {count: 0};
for (var i=0; i<$scope.users.length; i++){
if ($scope.users[i].done) $scope.selection.count++;
}
And amend selection.count on each ng-change of selection:
<div ng-app="project" ng-controller="UsersController">
<input type="checkbox" ng-repeat="user in users"
ng-model="user.done"
ng-change="selection.count = selection.count + user.done * 2 - 1">
<div ng-hide="selection.count">Select something</div>
</div>
(Note, that it had I had to use an object selection that holds that property count; just using $scope.selectionCount would not have worked due to how prototypical inheritance works and the fact that ng-repeat creates a child scope)
I have an array of objects set up something like this:
$scope.people = [{name:
{last:"Doe", first:"John"}},
{name:
{last:"Smith", first:"Joe"}}];
and I'm trying to do a live filter by text box of last names.
Here's the jsfiddle: http://jsfiddle.net/HB7LU/4287/
Any help would be nice. Thank you!
Edit: sorry I put in the wrong jsfiddle
Taking your fiddle as starting point, I'd say:
HTML
<div ng-controller="MyCtrl">
<input ng-model="search" ng-init="search = ''" placeholder="enter search" />
<div ng-repeat="person in people | filter:{name.last: search}">
{{ person | json }}
</div>
</div>
JS
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.people = [{ name: { last: 'Doe', first: 'John' } },
{ name: { last: 'Smith', first: 'Joe' } }];
}
Here's the plunker http://plnkr.co/edit/W46Fkj
So create a filter!
Building off your existing code:
myApp.filter("search", function() {
return function(people, startPhrase) {
if(!startPhrase) {
return people;
}
var filtered = [];
for(obj in people) {
if(people[obj].name.last.indexOf(startPhrase) == 0) {
filtered.push(people[obj]);
}
}
console.log(filtered);
return filtered;
}
});
Now, you can use a filter called "search" anywhere in the HTML. Call it like this:
<div ng-controller="MyCtrl">
<input ng-model="search.name.last"/>
<div ng-repeat="person in people | search:search.name.last">
{{person.name.last}}, {{person.name.first}}
</div>
</div>
I have a list of check boxes, of which at least one is compulsory. I have tried to achieve this via AngularJS validation, but had a hard time. Below is my code:
// Code goes here for js
var app = angular.module('App', []);
function Ctrl($scope) {
$scope.formData = {};
$scope.formData.selectedGender = '';
$scope.gender = [{
'name': 'Male',
'id': 1
}, {
'name': 'Female',
'id': 2
}];
$scope.formData.selectedFruits = {};
$scope.fruits = [{
'name': 'Apple',
'id': 1
}, {
'name': 'Orange',
'id': 2
}, {
'name': 'Banana',
'id': 3
}, {
'name': 'Mango',
'id': 4
}, ];
$scope.submitForm = function() {
}
}
// Code goes here for html
<!doctype html>
<html ng-app="App">
<head>
<!-- css file -->
<!--App file -->
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js"></script>
<!-- External file -->
</head>
<body>
<div ng-controller="Ctrl">
<form class="Scroller-Container">
<div ng-app>
<form class="Scroller-Container" ng-submit="submit()" ng-controller="Ctrl">
<div>
What would you like?
<div ng-repeat="(key, val) in fruits">
<input type="checkbox" ng-model="formData.selectedFruits[val.id]" name="group[]" id="group[{{val.id}}]" required />{{val.name}}
</div>
<br />
<div ng-repeat="(key, val) in gender">
<input type="radio" ng-model="$parent.formData.selectedGender" name="formData.selectedGender" id="{{val.id}}" value="{{val.id}}" required />{{val.name}}
</div>
<br />
</div>
<pre>{{formData.selectedFruits}}</pre>
<input type="submit" id="submit" value="Submit" />
</form>
</div>
<br>
</form>
</div>
</body>
</html>
Here is the code in plunker: http://plnkr.co/edit/Bz9yhSoPYUNzFDpfASwt?p=preview Has anyone done this on AngularJS? Making the checkboxes required, forces me to select all the checkbox values. This problem is also not documented in the AngularJS documentation.
If you want to require at least one item in group being selected, it's possible to define dynamic required attribute with ng-required.
For gender radio buttons this would be easy:
<input
type="radio"
ng-model="formData.selectedGender"
value="{{val.id}}"
ng-required="!formData.selectedGender"
>
Checkbox group would be easy too, if you used array to store selected fruits (just check array length), but with object it's necessary to check if any of values are set to true with filter or function in controller:
$scope.someSelected = function (object) {
return Object.keys(object).some(function (key) {
return object[key];
});
}
<input
type="checkbox"
value="{{val.id}}"
ng-model="formData.selectedFruits[val.id]"
ng-required="!someSelected(formData.selectedFruits)"
>
Update:
const someSelected = (object = {}) => Object.keys(object).some(key => object[key])
Also keep in mind that it will return false if value is 0.
Thanks to Klaster_1 for the accepted answer. I've built on this by using ng-change on the checkbox inputs to set a local scope variable, which would be used as the ng-required expression. This prevents the running of someSelected() on every digest.
Here is a plunkr demonstrating this: http://embed.plnkr.co/ScqA4aqno5XFSp9n3q6d/
Here is the HTML and JS for posterity.
<!DOCTYPE html>
<html ng-app="App">
<head>
<meta charset="utf-8" />
<script data-require="angular.js#1.4.9" data-semver="1.4.9" src="https://code.angularjs.org/1.4.9/angular.js"></script>
<script src="script.js"></script>
</head>
<body>
<div ng-controller="AppCtrl">
<form class="Scroller-Container" name="multipleCheckbox" novalidate="">
<h3>What would you like?</h3>
<div ng-repeat="fruit in fruits">
<input type="checkbox" ng-model="formData.selectedFruits[fruit.name]" ng-change="checkboxChanged()" ng-required="!someSelected" /> {{fruit.name}}
</div>
<p style="color: red;" ng-show="multipleCheckbox.$error.required">You must choose one fruit</p>
</form>
<pre>Fruits model:
{{formData.selectedFruits | json}}</pre>
</div>
</body>
</html>
angular
.module('App', [])
.controller('AppCtrl', function($scope) {
var selectedFruits = {
Mango: true
};
var calculateSomeSelected = function() {
$scope.someSelected = Object.keys(selectedFruits).some(function(key) {
return selectedFruits[key];
});
};
$scope.formData = {
selectedFruits: selectedFruits
};
$scope.fruits = [{
'name': 'Apple'
}, {
'name': 'Orange'
}, {
'name': 'Banana'
}, {
'name': 'Mango'
}];
$scope.checkboxChanged = calculateSomeSelected;
calculateSomeSelected();
});
Okay maybe very late to the party but if you have an array of objects which you are looking at, the solution of just checking the length of array of selected objects worked for me.
HTML
<div ng-repeat="vehicle in vehicles">
<input type="checkbox" name="car" ng-model="car.ids[vehicle._id]" ng-required=" car.objects.length <= 0"> {{vehicle.model}} {{vehicle.brand}} <b>{{vehicle.geofenceName}}</b>
</div>
JS
$scope.vehicles = [{},{}] // Your array of objects;
$scope.car = {
ids: {},
objects: []
};
$scope.$watch(function() {
return $scope.car.ids;
}, function(value) {
$scope.car.objects = [];
angular.forEach($scope.car.ids, function(value, key) {
value && $scope.car.objects.push(getCategoryById(key));
});
}, true);
function getCategoryById(id) {
for (var i = 0; i < $scope.vehicles.length; i++) {
if ($scope.vehicles[i]._id == id) {
return $scope.vehicles[i];
}
}
}
I understand what is happening in this solution that you are checking all the checkbox options to know which one is clicked. But from what I know this is by far the easiest solution(to understand and implement) and it works like a charm if you know that your options will be limited.
For a more time optimized solution. Check the answers above.
We can achieve your requirement without traversing all check-boxes instance.
Here is the sample code
<script>
angular.module('atLeastOneExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.e = function(s){
eval(s);
};
}]);
</script>
Here i am wrapping javascript eval function in "e" function to access it.
<form name="myForm" ng-controller="ExampleController" ng-init="c=0">
<label>
Value1: <input type="checkbox" ng-model="checkboxModel.value[0]" ng-change="e('($scope.checkboxModel.value[0])?$scope.c++:$scope.c--')"/>
</label><br/>
<label>
Value2: <input type="checkbox" ng-model="checkboxModel.value[1]" ng-change="e('($scope.checkboxModel.value[1])?$scope.c++:$scope.c--')"/>
</label><br/>
value = {{checkboxModel.value}}<br/>
isAtLeastOneChecked = {{c>0}}
</form>