I'm trying to write something that lets me edit records with dates in them, I have this inside my table:
<tr ng-repeat="event in eventFixtures track by $index">
<td>{{event.date | date: 'dd/MM/yyyy'}}</td>
<td>
<div class="row">
<div class="col-md-6">
<p class="input-group">
<input type="text"
class="form-control"
ng-model="event.date"
is-open="fixture{{$index}}popup"
ng-click="openFixturePopup($index)"/>
</p>
</div>
</div>
</td>
</tr>
However when I go to click on one of the input boxes the datepicker doesn't show up.
The open function is here:
$scope.openFixturePopup = function(fixture) {
$scope["fixture"+fixture+"popup"] = true;
};
The variables are delcared like so:
for(var i = 0; i < data.length; i++) {
$scope["fixture"+i+"popup"] = false;
}
From having the values of the variables be printed out above the table, they are being changed and if I create an input that is linked to a specific fixture popup e.g. like this:
<div class="row">
<div class="col-md-6">
<p class="input-group">
<input type="text"
class="form-control"
uib-datepicker-popup="{{format}}"
ng-model="testDate"
is-open="fixture0popup"
ng-click="openFixturePopup(0)"/>
</p>
</div>
</div>
It works fine.
Does anyone know what might be causing this?
I have a hunch that trying to use interpolation for a variable name is what is throwing this off. I tried numerous things like $scope[dynamicVarName], $scope.$eval([dynamicVarName]), and others to no avail. I can't say for certain that is your issue, but I think I found a solution that you can try.
Set an isOpen flag on your event and look at that, rather than creating a bunch of scope variables for state. This is also advantageous because if the index changes, the open state moves with the array element, so there is less chance that you get invalid states.
Here's what the code could look like:
var app = angular.module("myApp", [])
.controller("myCtrl", function ($scope) {
$scope.eventFixtures = [
{name: "1", date: "1-1-01"},
{name: "2", date: "2-2-02"},
{name: "3", date: "3-3-03"},
{name: "4", date: "4-4-04"},
{name: "5", date: "5-5-05"}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<table>
<tr ng-repeat="event in eventFixtures track by $index">
<td>{{event.date | date: 'dd/MM/yyyy'}}</td>
<td>
<div class="row">
<div class="col-md-6">
<p class="input-group">
<input type="text"
class="form-control"
ng-model="event.date"
is-open="{{event.isOpen}}"
ng-blur="event.isOpen = false;"
ng-focus="event.isOpen = true;"/>
isOpen? {{event.isOpen || false}}
</p>
</div>
</div>
</td>
</tr>
</table>
</div>
Related
Is it possible to check that form is valid in js file, but for many objects? I want to have only one form in html and don't use any of ng-repeats or other loops in html, then check form is valid for all objects.
Exmaple
<!DOCTYPE html>
<html ng-app="AngularApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"> </script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body ng-controller="mainController">
Click on table row if u want to change data in form
<table>
<thead>
<tr>
<td>
Index
</td>
<td>
Name
</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="element in testCollection"
ng-click="changeActiveElement(element)">
<td>{{ $index }}</td>
<td>{{ element.name }}</td>
</tr>
</tbody>
</table>
<br />
<br />
<br />
<form name="exampleForm">
<div class="row">
Name [required]: <input type="text" ng-model="activeObject.name" required>
</div>
<div class="row">
Phone [required]: <input type="text" ng-model="activeObject.phone" required>
</div>
<div class="row">
Active: <input type="checkbox" ng-model="activeObject.active">
</div>
</form>
<br />
<button ng-disabled="">
This button should be enable if all objects from table will pass form validation
</button>
but how to do this? Button should be know that every form is good or not, even if won't change object by clicking on table row.
</body>
</html>
Js:
var app = angular.module("AngularApp", []);
app.controller('mainController', function($scope) {
$scope.testCollection = [
{
name: 'Mike',
phone: 12345678,
active: true
},
{
name: 'Martin',
phone: '',
active: false
},
{
name: 'Anna',
phone: '',
active: ''
}
];
$scope.activeObject = $scope.testCollection[0];
$scope.changeActiveElement = function(element) {
$scope.activeObject = element;
};
});
Yes its possible, so lets say that 'many objects' are like this :
$scope.fianlObject = { manyObj1 : {}, manyObj2 :{}}
then do something like this with HTML :
<form id="frm1" name="frm1" ng-submit="submit()">
<div class="form-group required" ng-class="isInvalid('manyObj1', form1)">
....
</div>
<div class="form-group required" ng-class="isInvalid('manyObj2', form1)">
....
</div>
.
.
</form>
and something like this with script :
$scope.isInvalid = function (manyObj, form) {
if (form&& form.$submitted) {
return ( form[manyObj] && form[manyObj].$invalid) ? 'has-error'
: '';
}
return '';
}
Angular have FormController, that have property $invalid
$invalid
boolean
True if at least one containing control or form is invalid.
and you can use it like
<button ng-disabled="formName.$invalid" ... >
Yes, you can do that.
Just specify you validator function as a pure function which just accepts a plain object with the data and returns an array of errors (empty if everything is ok). This function should know about context it's used in.
Simple example:
function validateForm(data) {
var errors = [];
if (data.name === 'Joe') errors.push("You can't be Joe!");
return errors;
}
Then, every time you want to validate your form, convert your form data to JS object and use the function. Also, you can use such function in any other context, no matter who is initiator of the validation.
Following is my code in which I am not getting selected radio option for each corresponding rows, let me know what I am doing wrong here.
My Plnkr Code - http://plnkr.co/edit/MNLOxKqrlN5ccaUs5gpT?p=preview
Though I am getting names for classes object but not getting the selection.
HTML code -
<body ng-controller="myCtrl">
<div class="container-fluid">
<form name="formValidate" ng-submit="submitForm()" novalidate="" class="form-validate form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label">Name</label>
<div class="col-sm-6">
<input type="text" name="name" required="" ng-model="classes.name" class="form-control" />
</div>
</div>
<div class="form-group">
<table id="datatable1" class="table table-striped table-hover">
<tr class="gradeA" ng-repeat="cls in reqgrps">
<td ng-bind="cls.name"></td>
<td><input type="radio" name="groupName[{{$index}}]" ng-model="classes.satisfies"> Choice 1</td>
<td><input type="radio" name="groupName[{{$index}}]" ng-model="classes.satisfies"> Choice 2</td>
<td><input type="radio" name="groupName[{{$index}}]" ng-model="classes.satisfies"> Choice 3</td>
</tr>
</table>
</div>
<div class="panel-footer text-center">
<button type="submit" class="btn btn-info">Submit</button>
</div>
</form>
</div>
<div class="result">{{classes}}</div>
</body>
Script File -
var myApp = angular.module('myApp', []);
myApp.controller('myCtrl', function($scope){
$scope.reqgrps = [{name: 'Sub1', roll: 121},{name: 'Sub2', roll: 122}, {name: 'Sub3', roll: 123}];
$scope.classes = {};
$scope.result = {};
$scope.submitForm = function() {
$scope.result = $scope.classes;
};
});
------------- EDIT -------------
Expected Output -
classes obj -
{
name: "Test Class",
satisfies: [
"Sub1": "Choice 1",
"Sub2": "Choice 3",
"Sub3": "Choice 2",
.................
..................
..................
..................
"Subn": "Choice 2",
]
}
You'll need to differentiate between each row that is generated by ng-repeat.
You can do this by adding [$index] to each ng-model like this:
<td><input type="radio" ng-model="classes.satisfies[$index]" value="Choice 1"> Choice 1</td>
<td><input type="radio" ng-model="classes.satisfies[$index]" value="Choice 2"> Choice 2</td>
<td><input type="radio" ng-model="classes.satisfies[$index]" value="Choice 3"> Choice 3</td>
As others have mentioned, you can make the result dynamic as needed by using ng-value to set the value that is passed into the model.
The resulting object is something like this:
{"name":"Bill","satisfies":{"0":"Choice 2","1":"Choice 1","2":"Choice 3"}}
See plunker here
You should specify a different ng-model property for each row. (Not sure why you'd want to specify the same model on 3 identical rows). In theory you don't HAVE to do this, but as I said, I don't see why you would.
Also you should add a value attribute on your radio buttons:
http://plnkr.co/edit/JN4JuQJH2OvRxoawfDbv?p=preview
From the angular docs:
value string
The value to which the expression should be set when selected.
https://docs.angularjs.org/api/ng/input/input%5Bradio%5D
I would also recommend removing the initialization of empty objects in your controller (if ng-model doesn't find the property on the scope it will just create it for you), and I've noticed you've used ng-bind, in case you didn't know that's just a shortcut for the double brackets: {{}}
EDIT:
In case your value needs to be a dynamic value you can use ng-value and specify a property on the scope which you can then set in your controller
You need to set ng-value for each radio button, so than Angular will be able to pick those values. You have 3 identical rows so I added some dummy values for them to show the right output.
http://plnkr.co/edit/AxUx83xdotniYru6amGU?p=preview
Also, you can find an explicit example of using Angular radio buttons in official docs here:
https://docs.angularjs.org/api/ng/input/input%5Bradio%5D
UPDATE:
Check edited plnkr, hope it helps!
I'm fairly new to angular, so hopefully this is a super simple question for someone to nail.
I have a form (cut down version below) that I want to be able to have a live preview being shown as the user fills in the form.
All was going well with standard fields, however I've hit a roadblock with <select> fields.
<div ng-app="jobcreate">
<div class="row fullWidth" ng-contoller="JobCtrl">
<div class="medium-6 columns">
<form method="POST" action="http://localhost:3030/job/create" accept-charset="UTF-8">
<label for="title">Enter a title</label>
<input placeholder="title" id="title" required="required" ng-model="job.title" name="title" type="text" />
<br />
<label for="title">Pick template</label>
<select ng-model="job.template" ng-options="template.Name for template in templates" name="template"></select>
</form>
</div>
<div class="medium-6 columns">
<div class='job-detail {{ job.template || "default" }}'>
<h2>{{ job.title || "Enter a title"}}</h2>
<h2>{{ job.template || "Pick a template"}}</h2>
<pre>Templates: {{templates | json}}</pre>
</div>
</div>
</div>
</div>
And here is the js:
angular.module('jobcreate', []).controller('JobCtrl', function($scope) {
$scope.templates = [
{ID:'default', name:'Default'},
{ID:'obnoxious', name:'Obnoxious'}
];
});
I have a jsfiddle here so you can see it in action: http://jsfiddle.net/2m8jm/4/
As you can see, entering something in the title field works as intended, but I'm struggling to get the contents of the $scope.colors to fill in the select field
In your fiddle : http://jsfiddle.net/2m8jm/4/, you have choosed templates as an data array for ng-options but there is not scope variable named templates in the controller JobCtrl. I have renamed $scope.colors to $scope.templates and modified the ng-options bit - ng-options="template.ID as template.name for template in templates".
Here is a working plunker : http://plnkr.co/edit/wsbxkjRqTEU2yfcHOV0D?p=preview
Update
Is there a way to not have the first empty value be in the select field?
Yes, Couple of ways.
1) Initialize job.template with some default value in your markup as :
<label for="title" ng-init="job.template='obnoxious'">Pick template</label>
<select ng-model="job.template" ng-options="template.ID as template.name for template in templates" name="template"></select>
2) Define controller as follows to set default value for job.template inside the controller :
.controller('JobCtrl', function($scope) {
// some other codes
$scope.job = {};
$scope.job.template = 'default';
});
I need to duplicate some input fields in order to handle data from clients. I have done it with jQuery http://jsfiddle.net/m7R3f/1/
HTML:
<fieldset id="fields-list">
<div class="pure-g entry">
<div class="pure-u-1-5">
<input type="text" class="pure-input-1" id="input-1" name="input-1">
</div>
<div class="pure-u-1-5">
<input type="text" class="pure-input-1" id="date" name="date">
</div>
<div class="pure-u-1-5">
<input type="text" class="pure-input-1" id="input-2" name="input-2">
</div>
</fieldset>
<button id="add">Add</button>
JS
$(document).ready(function ()
{
$("#add").click(function ()
{
$(".entry:first").clone(false).appendTo("#fields-list");
});
});
However I just start learning Angular and want to convert these code to Angular.
I have read questions in stackoverflow and found the code with angularjs here: http://jsfiddle.net/roychoo/ADukg/1042/. However, it seem works only for ONE input field? Can I clone/duplicate several input fields using AngularJS? (in other word: convert my code above into AngularJS version?)
Thank you very much.
If you want to clone html element, the best way to use ng-repeat directive.
Your Controller
var App = angular.module('App', []).controller('Test', ['$scope',
function($scope) {
$scope.inputCounter = 0;
$scope.inputs = [{
id: 'input'
}];
$scope.add = function() {
$scope.inputTemplate = {
id: 'input-' + $scope.inputCounter,
name: ''
};
$scope.inputCounter += 1;
$scope.inputs.push($scope.inputTemplate);
};
}
])
<!DOCTYPE html>
<html ng-app="App">
<head lang="en">
<meta charset="UTF-8">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body ng-controller="Test">
<fieldset id="fields-list">
<div class="pure-g entry" ng-repeat="input in inputs track by input['id']">
<div class="pure-u-1-5">
<input type="text" class="pure-input-1" id="input" name="input-1">
</div>
<div class="pure-u-1-5">
<input type="text" class="pure-input-1" id="date" name="date">
</div>
<div class="pure-u-1-5">
<input type="text" class="pure-input-1" id="input-2" name="input-2">
</div>
</div>
</fieldset>
<button type="button" id="add" ng-click="add()">Add</button>
</body>
</html>
Angular prevents of creation duplicated elements, to avoid this, use track by like in the example
You should create an array and use ng-repeat in your HTML. Each object in the array can contain the data necessary to populate your divs. If you want to start with three entries, then add the data for those three. If you want to add more, then simply push onto the array. Because of Angular's 2-way data binding your form field will appear once the element is pushed onto the array.
For more details on how to do this, checkout the To Do example on Angular's home page.
How about this(Fiddle)
add two more ng-model and push those models
$scope.add = function(){
$scope.items.push($scope.newitem1,$scope.newitem2,$scope.newitem3);
}
There are three fields(first name, Last name & age) displayed in text boxes. Each field is displayed in separate div's. There are 4 records. On clicking a sort button above each field the div records should be sorted based on the data type of the field and should displayed in the HTML page.
I tried the solution in this link
I can't use this because the records are displayed in text box within the div.
<div id="content">
<div>
<div class="price"><input type="text" class="pri" value="120"/></div>
<div class="dateDiv">2012-05-09 20:39:38.0</div>
<div class="distance">20 mile</div>
</div>
<div>
<div class="price"><input type="text" class="pri" value="123"/></div>
<div class="dateDiv">2012-05-10 20:39:38.0</div>
<div class="distance">30 mile</div>
</div>
<div>
<div class="price"><input type="text" class="pri" value="100" /></div>
<div class="dateDiv">2012-05-11 20:39:38.0</div>
<div class="distance">50 mile</div>
</div>
<div>
<div class="price"><input type="text" class="pri" value="124"/></div>
<div class="dateDiv">2012-05-12 20:39:38.0</div>
<div class="distance">60 mile</div>
</div>
</div>
How can I do this in javascript?
see this demo using jquery.tinysort.min.js
see also this one
You can use knockoutjs to do something like that.
For example, the html:
<div id="content" data-bind="foreach: lines">
<div class="fname"><input type="text class="pri" data-bind="value: fname"/></div>
<div class="lname" data-bind="text: lname"/>
<div class="age" data-bind="text: age"/>
</div>
Javascript:
function EachDivViewModel(line)
{
this.fname = line.fname;
this.lname = line.lname;
this.age = line.age;
}
function YourViewModel()
{
var self = this;
self.lines = ko.observableArray([]); // this array will contain elements of EachDivViewModel type
self.handlerForYourSortButtongs = function() {
// Code here to sort the array based on the button clicked
// The UI will automatically get updated as you reorder the elements in the lines array
}
}
$(document).ready(function() {
var yourViewModelInstance = new YourViewModel();
// Code to get the lines here
ko.applyBindings(yourViewModelInstance);
});
It can be done using tablesorter.
Hope that will help you out.