I have a form element:
<form name="formDate">
<input date-picker name="fundacao" ng-model-date="fTit.fundacao" required>
</form>
And the directive:
app.directive('datePicker', function(){
return {
restrict: 'A',
scope: {
ngModelDate: "=ngModelDate"
},
link: function (ng, el, attr) {
// $validators HERE
}
};
})
The "required" validation does not work because there is no ng-model directive on the element.
Is there any way to validate a form with nonstandard directives, such as the example above?
you can bind change function on element
app.directive('datePicker', function(){
return {
restrict: 'A',
scope: {
ngModelDate: "=ngModelDate"
},
link: function (ng, el, attr,ctrl) {
el.bind('change',function(){
//check the $(el).val();
var isValid= the date is valid;
ctrl.$setValidity('date',isValid);
// the first param is the validation key, the second param is true if valid false if invalid
})
}
};
})
Related
I'm using the following dependencies:
angularJS v1.5.5
jquery v1.12.4
jquery-ui v1.12.1
jQuery Autocomplete plugin v1.2.6
I then define the directive like this:
.directive('autoComplete', [
'$timeout', function($timeout) {
return function(scope, element, attrs) {
var auto;
auto = function() {
$timeout((function() {
if (!scope[attrs.uiItems]) {
auto();
} else {
element.autocomplete({
source: [scope[attrs.uiItems]]
});
}
}), 0);
};
return auto();
};
}
])
which I borrowed from the answer to this SO question. The autocomplete works for the most part but when I move across the matches with the keyboard and press return or click on the match with the mouse, the model is updated with only the part that I typed and not with the full item selected. Where should I look to fix this? is it a bug in the plugin? directive? my input definition?
$scope.ccyPairs = [ "USDCHF", "CHFUSD", "USDEUR", "EURUSD", "USDGBP", "GBPUSD", "USDJPY", "JPYUSD", "CHFEUR", "EURCHF", "CHFGBP", "GBPCHF", "CHFJPY", "JPYCHF", "EURGBP", "GBPEUR", "EURJPY", "JPYEUR", "GBPJPY", "JPYGBP" ];
<input type="text" auto-complete id="ccyPair" ui-items="ccyPairs" ng-model="ccyPair" />
When I do:
$scope.$watch("ccyPair", function(newValue, oldValue) {
console.log(newValue);
}, false);
I see that the model is updated only with the part that I type in the input and not with the full selected match in the list either selecting it with a mouse click or moving across the matches and pressing enter.
For example, in the picture below, the model is updated to USD only and not to the correct full match CHFUSD.
OK after a lot of agony I crawled my way into a working solution :)
.directive('autoComplete', [
'$timeout', function($timeout) {
return {
require: 'ngModel',
link: function($scope, element, attrs, ctrl) {
var fAutoComplete;
fAutoComplete = function() {
$timeout(function() {
if (!$scope[attrs.uiItems]) {
fAutoComplete();
} else {
element.autocomplete({
source: [$scope[attrs.uiItems]]
}).on('selected.xdsoft', function(e, newValue) {
ctrl.$setViewValue(newValue);
$scope.$apply();
});
}
}, 5);
};
return fAutoComplete();
}
};
}
])
I tried to convert the normal jQuery own carousel into Angular Directive. It doesn't work for me, show some angular errors which I couldn't find what is the issue.
Controller
$scope.defaultsCarousel = {
'items': 4,
'itemWidth': 300,
'itemsDesktop': [1260, 3],
'itemsTablet': [930, 2],
'itemsMobile': [620, 1],
'navigation': true,
'navigationText': false
};
HTML (Jade)
custom-carousel(data-options="{{ defaultsCarousel }}", productid="#pl-1")
Directive
myApp.directive('customCarousel', function(){
function nextSlide(e) {
e.preventDefault();
e.data.owlObject.next();
};
function prevSlide(e) {
e.preventDefault();
e.data.owlObject.prev();
};
return{
restrict: 'E',
scope: {},
link: function($scope, el, attrs){
var options = $scope.$eval($(el).attr('data-options'));
var product_id = attrs.productid;
console.log(product_id);
$(product_id).owlCarousel(options);
var owl = $(product_id).data('owlCarousel');
$(product_id).parent().find('.slide-control.right').on('click', {owlObject: owl}, nextSlide);
$(product_id).parent().find('.slide-control.left').on('click', {owlObject: owl}, prevSlide);
}
}
ERROR
Syntax Error: Token '{' invalid key at column 2 of the expression [{{] starting at [{4}].
Your problem is at this line $scope.$eval($(el).attr('data-options'));. This produce a parse syntax error. You have two options to fix it:
OPTION 1: get the options from attrs parameter of link directive function. (PLUNKER)
app.directive('customCarousel', function() {
return {
restrict: 'E',
link: function(scope, el, attrs) {
var options = angular.fromJson(attrs.options);
var product_id = attrs.productid;
//..Rest of your logic
}
}
});
OPTION 2: get the options using scope one way binding. (PLUNKER)
app.directive('customCarousel', function() {
return {
restrict: 'E',
scope: {
options: '#',
productid: '#'
},
link: function(scope, el, attrs) {
var options = angular.fromJson(scope.options);
var product_id = scope.productid;
//..Rest of your logic
}
}
});
As you can see I'm getting the html data-options attribute as just options. That's because angularjs directives will ignore data-* prefix in all HTML elements and attributes names.
More info:
Check this post about difference between ng-app and data-ng-app
Check basic data-* prefix docs in W3Schools
I'm working on an angular wrapper for the jquery-knob widget. The following works as long as the maximum value doesn't change. If it does, the ng-model binding is lost. If I don't destroy the knob widget at the beginning of the watch, the max value doesn't change.
//Directive
app.directive('knobWidget', function () {
return {
scope: {
maxbinding: "=maxbinding",
maxbindingprop: "#maxbindingprop"
},
restrict: 'A',
require: 'ngModel',
link: function (scope, elem, attrs, ngModel) {
ngModel.$render = function () {
$(elem).val(ngModel.$viewValue).trigger("change");
};
scope.$watch('maxbinding', function (newVal) {
$(elem).knob('destroy');
$(elem).knob({
min: 0,
max: scope.maxbinding[scope.maxbindingprop],
value: ngModel.$viewValue,
change: function (changeVal) {
scope.$apply(function () {
ngModel.$setViewValue(changeVal);
});
}
});
});
}
};
});
//Markup
<input knob-widget data-min="0" maxbinding="arr" maxbindingprop="length" ng-model="currentStop" />
Doing:
$(elem).knob('max', scope.maxbinding[scope.maxbindingprop]);
doesn't work either. Any ideas?
Using trigger('configure') followed by trigger('change') should do the trick
$(elem).trigger('configure', {
'max': scope.maxbinding[scope.maxbindingprop];
});
$(elem).trigger('change');
Source
I am using in my application angular.js and jquery autocomplete.
So, I would like to create an angular directive, which wrap jquery autocomplete:
'use strict'
angular.module('nsi')
.directive('autoComplete', function () {
return {
restrict: 'A',
scope: {
httpService: "=",
renderItem: '=',
ngModel: '=',
minLength: '=',
onSelect: '='
},
link: function (scope, elem) {
elem.autocomplete({
source: function (request, response) {
scope.httpService(request.term).then(function (data) {
response(
$.map(data.items, function (item) {
return scope.renderItem(item);
}
)
);
});
},
minLength: scope.minLength,
select: function (event, ui) {
if (scope.onSelect) {
scope.onSelect(ui.item.item);
}
scope.$apply(function () {
scope.ngModel = ui.item.item;
});
}
})
;
}
};
});
in my controller I initialize necessary parameters for it:
$scope.supplierRender = function(item){
return {
label: item.supplierName,
value: item.supplierName,
item: item
}
};
$scope.httpSupplierService = function(suggest){
return SupplierService.getSuppliers('%' + suggest + '%');
};
$scope.supplierSelect = function(val) {
$scope.employee.supplier.id = val.id;
};
In my html view I start my directive:
<input type="text"
auto-complete
min-length="3"
http-service="httpSupplierService"
render-item="supplierRender"
on-select="supplierSelect"
ng-model="employee.supplier"
class="form-control"
value="employee.supplier.supplierName" />
The problem is, that when I am opening my employee in edit window, in autocomplete input i see [object Object]. So the queston is: "How to bind ngModel to employee.Supplier", and value of input to specific field of object (employee.supplier.supplierName)
Try to set ng-model:
ng-model="employee.supplier.supplierName"
Generally <input> takes value from directive ng-model so you don't need provide value=..
This is a test: Fiddle
The value=.. attribute works when ng-model not defined for input
I am trying to write a directive for the jeditable plugin so when it changes the value, it will change also edit the model of the edited element.
So i wrote something like that, JS Fiddle
but i don`t know how to get the object that bound to the object in the list.
JS:
var app = angular.module("app", []);
app.controller('ctrl', function ($scope) {
$scope.lst = [{
id: 1,
name: "item1"
}, {
id: 1,
name: "item1"
}, {
id: 2,
name: "item2"
}, {
id: 3,
name: "item3"
}, {
id: 3,
name: "item3"
}];
});
app.directive('uiEditable', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.editable("/echo/json/", {
onblur: 'submit',
onsubmit: function (response, settings) {
//here i need to update the model
}
});
}
};
});
This uses ngModel to update back to the model. (so don't forget ng-model on element)
app.directive('uiEditable', function () {
return {
restrict: 'A',
require: '?ngModel',
link: function (scope, element, attrs, ngModel) {
if (!ngModel) return; // do nothing if no ng-model
element.editable(function (val) {
var tVal = $.trim(val);
if (ngModel.$viewValue !== tVal)
scope.$apply(function () { return ngModel.$setViewValue(tVal); });
return tVal;
});
}
};
});
Why are you using the jeditable plugin? This plugin seems to only duplicate in jQuery what you could already do in angular using ng-model alone and no plugin required.
If you just want to create text which can be edited in place like jEditable does, instead of creating a custom directive simply using ng-submit, ng-click, ng-hide and ng-model. Here's a rough example.
The view:
<form ng-submit="submit()">
<div ng-hide="showEdit"
ng-click="showEdit = true">
{{foo.bar}}
</div>
<div>
<input type="text"
ng-show="showEdit"
ng-model="foo.bar" />
</div>
<a href="#" ng-show="showEdit"
ng-click="submit();">done</a>
</form>
And the controller:
app.controller('myCtrl', function($scope) {
$scope.foo = {
bar: 'some text'
};
$scope.showEdit = false;
$scope.submit = function() {
// hide the edit field
$scope.showEdit = false;
// submit form
console.log('submit form');
}
});
Pass your item in in an isolated scope:
app.directive('uiEditable', function(){
return {
restrict: 'A',
scope: {
item: '='
},
link: function(scope, element, attrs){
element.editable("/echo/json/", {
onblur: 'submit',
onsubmit: function(response, settings){
alert(scope.item);
}
});
}
};
});
'scope.item' will now give you a reference to the item inside your directive.