I have an AngularJS app that displays several plots. Each plot has a set of date controls to allow the user to change the start and end dates of the plotted data range. The date controls are loaded as a partial template in a uib-popover.
I've been using separate partial templates for each plot. I include the template in the page between <script type="text/ng-template"></script> tags, and load it using <button uib-popover-template="foo">Controls</button>.
This works fine, but having separate templates for each plot seems very repetitive, especially since I have several plots on the page. I tried creating a single template, setting the name of the plot for that "instance" of the template using ng-init, and hoping that would allow me to dynamically load the plot values into the template for that particular plot. Something along the lines of this:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.plots = {
"goodPlot": {
"start": "1/1/2018",
"end": "1/1/2019"
},
"betterPlot": {
"start": "5/5/2018",
"end": "3/10/2019"
}
};
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<div ng-app="myApp" ng-controller="myCtrl">
<h4>First Plot</h4>
<div ng-init="thisPlot = plots.goodPlot" ng-include="'plotControls.tmpl'"></div>
<hr/>
<h4>Second Plot</h4>
<div ng-init="thisPlot = plots.betterPlot" ng-include="'plotControls.tmpl'"></div>
<script type="text/ng-template" id="plotControls.tmpl">
<div class="form-group">
<label class="control-label">Start Date</label>
<input type="text" class="form-control" ng-model="thisPlot['start']">
</div>
<div class="form-group">
<label class="control-label">End Date</label>
<input type="text" class="form-control" ng-model="thisPlot['end']">
</div>
</script>
</div>
But as you can see, the start/end dates for both plots are the same. I understand why this is -- they're both binding to the same variables. But I can't figure out a solution to achieve the desired result.
Basically, I'm looking to create multiple "instances" of the same template, but with different variable values to be set before the ng-include.
Can anyone offer any suggestions?
Use a component to instantiate the template:
app.component("myPlotControls", {
bindings: { "plot", "<" },
templateUrl: "plotControls.tmpl",
})
Usage:
<my-plot-controls plot="plots.goodPlot"></my-plot-controls>
<my-plot-controls plot="plots.betterPlot"></my-plot-controls>
<script type="text/ng-template" id="plotControls.tmpl">
<div class="form-group">
<label class="control-label">Start Date</label>
<input type="text" class="form-control" ng-model="$ctrl.plot['start']">
</div>
<div class="form-group">
<label class="control-label">End Date</label>
<input type="text" class="form-control" ng-model="$ctrl.plot['end']">
</div>
</script>
Components create an isolate scope so that multiple instantiations of the same template will not conflict in the parent scope.
For more information, see
AngularJS Developer Guide - Creating Custom Components
Related
Clone div is repeating, when I click add button.
How can I post the fields inside clone div.
<div class="row" id="append-row">
<div class="clone-div-{{count}}" id="clone-div">
<div class="col-md-6">
<div class="form-group input-group-sm">
<label>Title</label>
<input type="text" class="form-control" id="addTitle" placeholder="Title" ng-model="chapters.chapter.title">
</div>
</div>
<div class="col-md-6">
<div class="form-group input-group-sm">
<label>Select Language</label>
<select class="form-control" name="country" id="country" ng-model="chapters.chapter.languageID" ng-options="value.ID as value.language for value in technical.languages">
<option value="">Select Country</option>
</select>
</div>
</div>
</div>
</div>
This part is angularjs code.
$scope.count = 1;
$scope.addChapter = function() {
var iEl = angular.element( document.querySelector('#append-row') );
var wEl = angular.element( document.querySelector('#clone-div') );
iEl.append(wEl.clone());
$scope.count+=1;
};
You should do cloning/repeating inside the template in a ng-repeat and have the data prepared beforehand, that is a much cleaner way. You'll notice for example in the template code you have, all the ng-model's are the same, and will always display the same information if you have 1 'clone' div or 100.
A better method would be to write your clone div in the template and use it as a repeatable ng-template 'script', for example:
// main template
<script type="text/ng-template" id="cloneable.html">
// Your code here, but change reference to ng-model, ie this line as an example:
<input type="text" class="form-control" id="addTitle" placeholder="Title" ng-model="chapters.chapter[$index].title">
</script>
// main template, your new repeat then includes the repeatable script
<div ng-repeat="foo in manyFoos"
ng-include="'cloneable.html'"></div>
This way you can use the $index that arises from ng-repeat, as part of the model to accurately separate each individual repeat block. In your controller, chapters.chapter will be an array of objects.
I don't know about the 'add' button part or what information you're adding, but the above should take care of the model problem you'll be encountering.
this code is not working i want to set min and max value to date is there any possibility to set value only useing html
<html>
<head>
<title>Date test</title>
</head>
<body>
<form>
<div class="list">
<div class="row">
<label class="item item-input">
<input type="date" placeholder="Meeting Date" name="mtgDate" ng-model='lead.meetingDate' ng-readonly="isReadonly" min="02/11/2015" max="01/12/2015">
</label>
</div><br>
<div class="row">
<label ng-show="frm.date.$dirty&&frm.date.$error.min" style="color:red;">below limit</label>
<label ng-show="frm.date.$dirty&&frm.date.$error.max" style="color:red;">Above limit</label>
</div>
</div >
</form>
</body>
</html>
html 5 has a new attribute for input type date
you can specific a field for date only like this
<input type="date" name="date" min="2015-11-02" max="2015-12-31">
Beware that not all browser has implemented this method. If you want cross browser compatibility, it is best to use JavaScript.
Here is a list of browser that supported date type attribute Browser supported list
Here is a working example (at least it worked in Chrome) Date Example
Here is a W3 spec on input type date W3.org
<div ng-app="">
<input type="text" ng-model="data.message">
<h1>{{ data.message }}</h1>
<div ng-controller="FirstCtrl">
<input type="text" ng-model="data.message">
<h1>{{ data.message }}</h1>
</div>
<div ng-controller="SecondCtrl">
<input type="text" ng-model="data.message">
<h1>{{ data.message }}</h1>
</div>
</div>
This is the HTML code they had to demonstrate "Sharing Data Between Controllers" but the bindings inside FirstCtrl and SecondCtrl didn't work for me. Is this way of binding not included in Angular 1.3?
Controllers
function FirstCtrl($scope) {
}
function SecondCtrl($scope) {
}
Original Tutorial Link
Fiddle
As of angular 1.3 you can no longer use global functions as controllers, you must explicitly add them to your module.
Name your module in your markup ng-app="my-app"
Create a module in code var app = angular.module('my-app', []);
Add your controllers to the module app.controller('FirstCtrl', FirstCtrl)
Enjoy data binding
Assume an certain amount of forms created by ng-repeat, which allows the user to sum something up like a+b and display the result instantly.
How would the Controller look like?
<div data-ng-repeat="form in forms">
<form name={{form.name}}>
<input type="text" name="a" ng-modal="?">
<input type="text" name="b" ng-modal="?">
</form>
<p>{{?.result}}</p>
</div>
The question marks within the html should be something unique I guess. And the controller may access something like an array of forms from scope ... but maybe someone has a suggestion
If I understand your question correctly and assuming you have defined the forms in an array for example, below code should work for you:
<!DOCTYPE html>
<html data-ng-app="formApp">
<head>
<script type="text/javascript" src="https://code.angularjs.org/1.2.26/angular.js"></script>
<script type="text/javascript">
var formApp = angular.module("formApp",[]);
formApp.controller("formController", function($scope)
{
$scope.forms = [{name: "Foo"}, {name: "Bar"}];
});
</script>
</head>
<body data-ng-controller="formController">
<div data-ng-repeat="form in forms">
<form name={{form.name}}>
<input type="text" name="a" data-ng-model="form.someField">
<input type="text" name="b" data-ng-model="form.someOtherField">
</form>
<p>{{form.someField + form.someOtherField}}</p>
</div>
</div>
</html>
So basically you were right when mentioning "array of forms from scope".
The important thing to know is that angular creates a new scope for every item in the collection when using ng-repeat. This means, you do not need to use unique member names. "form.someField" for example always references the member of the current scope.
The calculation you would like to perform could be done inline as in my example or you could move it to an own method on a "class" from which all items in the form collection will inherit.
By the way: it's "data-ng-model" and not "data-ng-modal" ;)
On a registration form I allow a user to enter zero or more phone numbers. Each phone number consists of a prefix and a number, these are two fields per phone number. The user may decide how many numbers he wants to provide, the add more numbers link would clone this part of the form.
Prefix: [_______]
Number: [_______]
+ add more numbers
The model I bind to is fixed and should be this format:
$scope.model = {
"...main inputs": "username, etc...",
phoneNumbers: [
// for each phone number I expect this object
{ "prefix": "+1", "number": "123123123" }
]
};
I am not sure how I should set up my ng-model for these text inputs to have these objects generated within the array.
Also, I am a great fan of referential binding and limiting things like scope watch and event-based changes to the scope, as often these changes go unnoticed for other directives that may be using this value (unless being watched). Basically that means it is my intention to have dynamic generation of objects within the array as the form is filled in with numbers, or dynamic removal of objects within the array as numbers are removed or both inputs left empty.
The array should only contain valid and filled objects, partially filled objects or empty objects should not be added to the model or array (as usually is done with properties with invalid values -- those properties get removed from the model object). Basically a push to the array with every validated object, and removal (slice) of objects for every invalid object. But then rather automatically, instead of writing a push/slice function.
Hi try out this code:
Html:
<form name="form">
<div data-ng-repeat="phone in phoneNumberArray">
<div class="form-group">
<label for="inputFirstName">Prefix</label>
<input id="prefix" class="form-control" type="text" ng-model="phone.prefix">
</div>
<div class="form-group">
<label for="inputLastName">Phone number</label>
<input id="phoneNumber" class="form-control" type="text" ng-model="phone.phoneNumber">
</div>
</div>
</form>
<div class="form-group">
<input type="submit" class="btn btn-primary" value="Add more number" data-ng-click="addmore()"/>
</div>
Controller:
$scope.phoneNumberArray = [
{
prefix: "",
phoneNumber:"",
}];
$scope.addmore = function () {
$scope.phoneNumberArray.push({
prefix: "",
phoneNumber: "",
});
}
Hi check this demo in Fiddle
Use the following code.....
<!DOCTYPE html>
<html>
<head>
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
</head>
<body ng-app ng-controller="todoCtrl">
<form name="form" ng-submit="addmore()">
<div class="form-group">
<label for="inputFirstName">Prefix</label>
<input class="form-control" type="text" ng-model="phone_prefix"/>
</div>
<div class="form-group">
<label for="inputLastName">Phone number</label>
<input class="form-control" type="text" ng-model="phone_Number"/>
</div>
<div class="form-group">
<input type="submit" class="btn btn-primary" value="Add more number"/>
</div>
</form>
<div ng-repeat="phone in phoneNumberArray">
{{ phone.prefix + " "+ phone.phoneNumber}}
</div>
<script>
function todoCtrl($scope) {
debugger;
$scope.phoneNumberArray = [
{prefix: '14', phoneNumber:'123'}
];
$scope.addmore = function () {
$scope.phoneNumberArray.push(
{prefix: $scope.phone_prefix, phoneNumber: $scope.phone_Number}
);
}
}
</script>
</body>
</html>