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
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 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
})
}
};
})
I am trying to build an application that uses angularjs and jquery mobile:
I have stumbled upon a problem when trying to filter model for jquery mobile slider.
The problem is that I need to modify data in directive (that is displayed for user) and that is used for further processing.
I found a posible way of achieving my goal on this post: Using angularjs filter in input element
However this doesn't work, probobly beause I am using compile function instead of link (because I need to trigger jquery slider create event before binding any data. If I don't do so, the neccessery markup for jquery mobile slider is not generated).
So anyway what happens is that after passing model trought another "filter" directive, the value is set to "1" even though it should be "50". And on top of that slider starts to act strangely, it only allows part of values to be set, for example "10" thought it should be "100".
Here's how I define my directives:
mcb.directive('jparser', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (s, e, a, ngModel) {
ngModel.$parsers.push(function (input) {
console.log('parser: ' + input);
return Math.round(input * 10);
});
ngModel.$formatters.push(function (input) {
console.log('formater: ' + input);
return Math.round(input / 10);
});
}
};
});
mcb.directive('jSlider', function () {
return {
scope: {
id: '#',
label: '#',
value: '=',
min: '=',
max: '=',
step: '#',
start: '&',
stop: '&'
},
restrict: 'A',
replace: false,
templateUrl: 'jslider.html',
compile: function (e) {
e.trigger('create');
return {
post: function (s, e, a) {
e.on('slidestart onfocus', function () {
return s.start();
});
e.on('slidestop', function () {
return s.stop();
});
e.on('focus', '.ng-valid-number', function () {
return s.start();
});
e.on('blur', '.ng-valid-number', function () {
return s.stop();
});
s.$watch('value', function (nv) {
console.log('nv:'+nv);
return e.find('#' + a.id).slider('refresh');
});
s.$watch('min', function () {
return e.find('#' + a.id).slider('refresh');
});
s.$watch('max', function () {
return e.find('#' + a.id).slider('refresh');
});
}
};
}
};
});
Sorry if it's messy question, I was trying to describe the problem as clear as possible.
Here's a plunker, with the problem in action: http://plnkr.co/edit/k8u0UgbIX8qLCGX1Yw3A?p=preview
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.