jQuery datepicker not working inside a AngularJS ng-repeat block.
Not sure if anything wrong in code generation inside ng-repeat block. The same logic works outside ng-repeat.
Working code
<div class="form-group">
<label class="control-label col-md-4">TEST DATE</label>
<div class="input-group col-md-2">
<input type="text" id="testDate" name="testDate" readonly="readonly" class="form-control">
</div>
</div>
Not working code
<div ng-repeat="reportType in reportTypes">
<div class="form-group">
<label class="control-label col-md-4">{{reportType.reportTypeLabel}}</label>
<div class="input-group col-md-2">
<input type="text" id="{{reportType.reportTypeCodeId}}Date" readonly="readonly"
class="form-control">
</div>
</div>
</div>
Javascript
// Date picker dd/mm/yyyy
$(function() {
$("input[id*='date']").datepicker({
dateFormat : "dd/mm/yy"
});
});
$(function() {
$("input[id*='Date']").datepicker({
dateFormat : "dd/mm/yy"
});
});
Use this directive to initialize the datepicker after ng-repeat ends:
angular.module('mymodule').directive('ngOnFinishRender', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
$timeout(function () {
scope.$emit(attr.broadcastEventName ? attr.broadcastEventName : 'ngRepeatFinished');
});
}
}
};
});
In your controller:
$scope.$on('ngRepeatFinished', function(){
$("input[id*='date']").datepicker({
dateFormat : "dd/mm/yy"
});
});
In your view, add the directive ng-on-finish-render to element with ng-repeat:
<div ng-repeat="reportType in reportTypes" ng-on-finish-render>
<div class="form-group">
<label class="control-label col-md-4">{{reportType.reportTypeLabel}}</label>
<div class="input-group col-md-2">
<input type="text" id="{{reportType.reportTypeCodeId}}Date" readonly="readonly"
class="form-control">
</div>
</div>
</div>
You can add broadcast-event-name="myNgRepeatFinished" parameter if you have more than one ng-repeat in your scope and they have different purposes
$scope.$on('myNgRepeatFinished', function(){
$("input[id*='date']").datepicker({
dateFormat : "dd/mm/yy"
});
});
You have to create a custom directive for the datepicker.
The View
<div ng-app="myApp" ng-controller="myController">
<div ng-repeat="report in repArray">
<div class="form-group">
<label>{{report.values.name}}</label>
<input type="text" datepicker ng-model="datevalue" />
</div>
</div>
The Directive
var myApp = angular.module('myApp', []);
myApp.controller('myController', ['$scope', function ($scope) {
$scope.report = [
{ 'name': 'rep1' },
{ 'name': 'rep2' },
{ 'name': 'rep3' }
]
$scope.repArray = Object.keys($scope.report)
.map(function (value, index) {
return { values: $scope.report[value] }
}
);
} ]);
myApp.directive("datepicker", function () {
function link(scope, element, attrs, controller) {
element.datepicker({
dateFormat: "dd/mm/yy"
});
}
return {
require: 'ngModel',
link: link
};
});
Related
I have a set of radio buttons inside a directive. The directive has an ng-repeat, so it exists multiple times.
I'm able to populate the input fields of the directive, but the radio buttons won't react.
angular.module('account-form-client-de', [])
.controller('ctrl', function($scope) {
$scope.owners = [];
$scope.addOwner = function() {
$scope.owners.push({
class: 'person',
name: 'new owner',
percentage: 0
});
}
$scope.addOwner();
$scope.addOwner();
})
.directive("newOwner", function() {
var options = {
restrict: 'E',
replace: true,
scope: {
owner: '=',
remove: '&'
},
link: function(scope, element, attrs, controller, $parent) {
},
template: `
<div class="table-owners item-row">
<div class="checkbox">
<input type="radio" name="type" ng-model="owner.class" value="person" validate-on-change>
<label for="person" translate>
table_owners.person
</label>
</div>
<div class="checkbox">
<input type="radio" name="type" ng-model="owner.class" value="company" validate-on-change>
<label for="company" translate>
table_owners.company
</label>
</div>
<input name="owners_name" ng-model="owner.name" type="text" placeholder="" class="form-control input-md">
<input name="owners_percentage" ng-model="owner.percentage" type="number" placeholder="" class="form-control input-md">
</div>`
};
return options;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="account-form-client-de" ng-controller="ctrl">
<pre>{{owners}}</pre>
<new-owner ng-repeat="owner in owners track by $index" owner="owner"></new-owner>
<button ng-click="addOwner()">add owner</button>
</div>
Since both the inputs and radio buttons refer to a property in the owner object, I fail to see why the inputs bind, and the radio buttons won't even become checked.
Any ideas?
It's because when you have the same directive multiple times, you have the same radio buttons with the same values multiple times. Then, the HTML parser gets confused. I fixed it by wrapping each row in a <form> (which you don't have to submit), so it's valid again.
angular.module('account-form-client-de', [])
.controller('ctrl', function($scope) {
$scope.owners = [];
$scope.addOwner = function() {
$scope.owners.push({
class: 'person',
name: 'new owner',
percentage: 0
});
}
// Add two owners to begin with
$scope.addOwner();
$scope.addOwner();
})
.directive("newOwner", function() {
var options = {
restrict: 'E',
replace: true,
scope: {
owner: '=',
remove: '&'
},
link: function(scope, element, attrs, controller, $parent) {
},
template: `
<form class="table-owners item-row">
<div class="checkbox">
{{owner.class}}
<input type="radio" name="person" value="person" ng-model="owner.class">
<label for="person" translate>
table_owners.person
</label>
</div>
<div class="checkbox">
<input type="radio" name="company" value="company" ng-model="owner.class">
<label for="company" translate>
table_owners.company
</label>
</div>
<input name="owners_name" ng-model="owner.name" type="text" placeholder="" class="form-control input-md">
<input name="owners_percentage" ng-model="owner.percentage" type="number" placeholder="" class="form-control input-md">
</form>`
};
return options;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="account-form-client-de" ng-controller="ctrl">
<pre>{{owners}}</pre>
<new-owner ng-repeat="owner in owners track by $index" owner="owner"></new-owner>
<button ng-click="addOwner()">add owner</button>
</div>
I have a web page that needs two datepickers, start date and end date. The problem is, whenever I click on the glyph to open the date selector, both date picker opens at the same time.
Here is my Template, Directive, Controller and how it's being used. Any help would be much appreciated.
Template:
<div class="input-group">
<input type="text" class="form-control" uib-datepicker-popup="dd/MM/yyyy" ng-model="start_date" is-open="popup.opened" datepicker-options="dateOptions" ng-required="true" close-text="Close" />
<span class="input-group-btn">
<button type="button" class="btn btn-default" ng-click="open()">
<i class="glyphicon glyphicon-calendar"></i>
</button>
</span>
</div>
Directive:
'use strict';
/*global angular*/
angular.module("myApp")
.directive("datepicker", function(){
return{
templateUrl: 'templates/datePicker.html',
controller: 'newDateCtrl',
replace: true
};
});
Controller
/*global angular*/
angular.module("myApp").controller("newDateCtrl", function($scope) {
$scope.popup = {
opened: false
};
$scope.open = function() {
$scope.popup.opened = true;
};
$scope.dateOptions = {
formatYear: 'yy',
maxDate: new Date(2020, 5, 22),
minDate: new Date(),
startingDay: 1
};
})
index.html, as part of a form like this:
....
<div class="form-group">
<label class="control-label col-sm-2">
Start Date
</label>
<div class="col-sm-10">
<datepicker></datepicker>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">
End Date
</label>
<div class="col-sm-10">
<datepicker></datepicker>
</div>
</div>
....
Two things:
- when declaring your directive, use an isolate scope.
i.e.
.directive('...', function() {
return {
.... // your existing stuff
scope: {} // this gives each directive instance isolated scope
}
});
I think also 'datepicker' is the name of the bootstrap directive already, so if you're wrapping it you should consider giving it a different name.
I want to post data to my asp.net webapi controller, by using $save() method that belong to ngResource i am getting this error:
"TypeError: $scope.product.$save is not a function at n.$scope.saveProduct "
when i used $http(), data is getting saved but $save() is giving me error, other methods like $query() and $get() are working properly only $save() is causing an error.
code:
// first file (module)
var app = angular.module('commonServices', ['ngResource'])
.constant('appSettings', {
serverPath: 'http://localhost:29904/'
});
//second file (factory)
(function(){
angular.module('commonServices')
.factory('productResource', ['$resource', 'appSettings', productResource])
function productResource($resource, appSettings) {
return $resource(appSettings.serverPath + "api/Products/:id",
null,
{
'update': { method: 'PUT' },
});
}
}());
// third file (controller)
myApp.controller('editProductController', ['$scope', '$routeParams', '$http', 'productResource',
function ($scope, $routeParams, $http, productResource) {
$scope.num = $routeParams.id;
$scope.alertUser = false;
$scope.saveProduct = function () {
$scope.product.$save(function(data){});
}
};
}]);
// some markup from template
<div class="form-group ">
<label class="col-md-2 control-label"
for="inputProductName">Product Name</label>
<div class="col-md-4">
<input class="form-control"
id="inputProductName"
name="inputProductName"
type="text"
placeholder="Product Name (required)"
required
ng-model="product.productName" />
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label" for="inputProductCode">Product Code</label>
<div class="col-md-4">
<input class="form-control"
id="inputProductCode"
name="inputProductCode"
type="text" ng-model="product.productCode">
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label"
for="inputAvailabilityDate">Availability</label>
<div class="col-md-4">
<div class="form-control">
{{product.releaseDate}}
</div>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label"
for="inputDescription">Description</label>
<div class="col-md-4">
<textarea class="form-control"
id="inputDescription"
name="inputDescription"
placeholder="Description"
rows="3" ng-model="product.description"></textarea>
</div>
<br />
</div>
<div class="form-group">
<div class="col-md-4 col-md-offset-2">
<span>
<button class="btn btn-primary"
style="width:80px;margin-right:10px" ng-click="saveProduct()">
Save
</button>
</span>
to use $save() without calling get what i do is here:
productResource.save($scope.product, function(data) {
});
Thanks #TzachOvadia for providing me a clue :)
Try this:
$scope.product = productResource.get({ id: $scope.num });
$scope.saveProduct = function () {
$scope.product.$save(function (response) {...});
}
in my app i try to use bootstrap datepicker
but i have one trouble: how to hide it on icon and some other field (if i will need) when it's is displayed?
my view:
<div class="input-group date custom">
<input type="text" id="date" data-ng-model="article.Date" name="date" class="form-control" required/><span class="input-group-addon"><i class="date-ico"></i></span>
</div>
and directive (it's declaration is on modal window):
.directive('dateClick', function ($window) {
return {
restrict: 'EA',
link: function (scope, element, attrs) {
var dateIcon = element.find('.date-icon');
dateIcon.bind('click', function () {
var datepckr = angular.element(document).find('.datepicker');
if (typeof datepckr[0] !== 'undefined'){
console.log('hide');
var datepckrMenu = angular.element(document).find('.datepicker.dropdown-menu');
datepckrMenu.datepicker('hide');
}
});
}
}
});
how could i hide my datepicker in the best way?
also i see that it didn't hide if i click in textAngular's editor...
you can try it me be it's help...
Live Demo
github Link
<div>
<div data-ng-controller="AppCtrl">
<input id="datepicker" type="text" data-ng-datepicker data-ng-options="datepickerOptions" data-ng-model="date">
<input id="datepickerMirror" type="text" data-ng-model="date">
</div>
</div>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/2.0.4/css/bootstrap.min.css">
<link rel="stylesheet" href="https://rawgit.com/cletourneau/angular-bootstrap-datepicker/master/dist/angular-bootstrap-datepicker.css">
<script src="http://code.jquery.com/jquery-2.0.2.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/2.0.4/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<script src="https://rawgithub.com/cletourneau/angular-bootstrap-datepicker/master/dist/angular-bootstrap-datepicker.js" charset="utf-8"></script>
Js Script
app = angular.module 'myapp', ['ng-bootstrap-datepicker']
AppCtrl = ($scope)->
$scope.datepickerOptions =
format: 'yyyy-mm-dd'
language: 'fr'
autoclose: true
weekStart: 0
$scope.date = '2000-03-12'
app.controller 'AppCtrl', AppCtrl
angular.bootstrap document, ['myapp']
I'm having a problem with AngularJs. I have created a directive that $watch the model and it takes some action based on the model's current status. However, although during debugging I can see that the $watch is set, it is only being triggered after the model get valid at least once and I don't know why that is happening. Debugging it doesn't even gets into the $watch function when something is typed.
The code is below:
Directive:
(function() {
'use strict';
var app = angular.module('app');
app.directive('tooltipValidation', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
var tooltip = $(element).qtip({
content: {
text: element.next('div')
},
show: false,
hide: true
}).qtip('api');
scope.$watch(attrs.ngModel, function() {
if (ngModel.$invalid && ngModel.$dirty) {
tooltip.show();
} else {
tooltip.hide();
}
});
}
};
});
})()
HTML:
<div class="form-address clearfix" ng-show="isNewShippingAddress" ng-form="newShippingAddressForm">
<h3>Include new shipping address:</h3>
<div class="novo-endereco clearfix" id="newAddress">
<div class="required address apelido">
<label for="newShippingAddressAlias">Alias</label>
<input id="newShippingAddressAlias" name="newShippingAddressAlias" type="text" tooltip-validation ng-model="newShippingAddress.Alias" required ng-maxlength="32" />
<div data-ng-show="newShippingAddressForm.newShippingAddressAlias.$dirty && newShippingAddressForm.newShippingAddressAlias.$invalid">
<p data-ng-show="newShippingAddressForm.newShippingAddressAlias.$error.required">obligatory</p>
<p data-ng-show="newShippingAddressForm.newShippingAddressAlias.$error.maxlength">max 32 char</p>
</div>
</div>
<div class="required endereco">
<label for="newShippingAddressStreet">Street</label>
<input id="newShippingAddressStreet" name="newShippingAddressStreet" type="text" tooltip-validation ng-model="newShippingAddress.Street" required ng-maxlength="256" />
<div data-ng-show="newShippingAddressForm.newShippingAddressStreet.$dirty && newShippingAddressForm.newShippingAddressStreet.$invalid">
<p data-ng-show="newShippingAddressForm.newShippingAddressStreet.$error.required">obligatory</p>
<p data-ng-show="newShippingAddressForm.newShippingAddressStreet.$error.maxlength">max 256 char</p>
</div>
</div>
<div class="required cep">
<label for="newShippingAddressZipCode">ZipCode</label>
<input id="newShippingAddressZipCode" name="newShippingAddressZipCode" type="text" tooltip-validation ng-model="newShippingAddress.ZipCode" required ng-pattern="/^[0-9]{8}$/" />
<div data-ng-show="newShippingAddressForm.newShippingAddressZipCode.$dirty && newShippingAddressForm.newShippingAddressZipCode.$invalid">
<p data-ng-show="newShippingAddressForm.newShippingAddressZipCode.$error.required">obligatory</p>
<p data-ng-show="newShippingAddressForm.newShippingAddressZipCode.$error.pattern">8 digits</p>
</div>
</div>
<input type="submit" class="button grey" value="Save new address" data-ng-click="saveShippingAddress()" ng-disabled="newShippingAddressForm.$invalid" />
</div>
</div>
Regards,
dimello
Try:
scope.$watch(function(){
return ngModel.$viewValue; //Watch for view value (the value in your input)
}, function() {
if (ngModel.$invalid && ngModel.$dirty) {
tooltip.show();
} else {
tooltip.hide();
}
});
DEMO
Explanation:
When you type an invalid value into the input with ng-model, the underlying model is not updated, causing your scope.$watch(attrs.ngModel not being fired because you're watching for changes in the model. If you need to fire the function every time the input changes no matter it's valid or not, try the above solution.