Make function always available, without calling it - angularjs

I want to validate max number of checked checkboxes.
I have this function and it works.
$('.Item:input').each( function (i, element) {
$(element).click(function() {
if ($('.Item:checked').length > 10) {
alert('error');
$(element).attr('checked', false)
}
})
});
Now i don't know how and where to call it in angular. I suppose to call it on ng-click event, but it works (obviously) only on the second click (first one only call the function)
Anyone can help me?

I solved it using data-ng-init instead of ng-click.

The code you have is for jquery, for angular approach is completly diffrent.
I have put an example.
http://jsfiddle.net/neolivz/8x15o1t4/
You can set up a model
<input type="checkbox" ng-model="test.value" ng-change ="updateCount(test)">
and do what you want in the updateCount api
$scope.updateCount = function(test){
if(test.value){
$scope.count++;
}else{
$scope.count--;
}
if($scope.count==10){
test.value = false;
$scope.count--;
return;
}
}

$viewContentLoaded event is emitted that means to receive this event you need a parent controller like:
<div ng-controller="MainCtrl">
<div ng-view></div>
</div>
From MainCtrl you can listen the event
$scope.$on('$viewContentLoaded', function(){
//Here your view content is fully loaded !!
});
Check the Demo.
I think this might solve your problem, or at least take you nearer to the solution.

Related

How do I get my changes to persist in Angular using 2-way Data Binding with an onDrag callback?

I am trying to update a span's text after a call back function in Angular.
Here is my HTML:
<div ng-controller="onDragController">
<div id="draggableArea">
<div id="rectangle1" data-drag="true" jqyoui-draggable="{onDrag: 'dragCallback'}" data-jqyoui-options="{containment: '#draggableArea'}"></div>
</div>
<div>
<span ng-model="rectangleOne">{{rectangleOne.leftOffset}}</span>
</div>
</div>
And my controller is:
var App = angular.module('drag-and-drop', ['ngDragDrop', 'ui.bootstrap']);
App.controller('onDragController', function($scope) {
$scope.rectangleOne = {};
$scope.rectangleOne.leftOffset = 'ASDF';
$scope.dragCallback = function (event, ui) {
$scope.rectangleOne = {leftOffset: '12345'};
};
});
If I toss an alert in my callback function then I am seeing that the leftOffSet is updated, but on my HTML page the {{rectangleOne.leftOffset}} is staying the same.
What am I missing here...?
Use $apply in your dragCallback as follows:
$scope.dragCallback = function(event, ui) {
$scope.$apply(function() {
$scope.rectangleOne = {
leftOffset: '12345'
};
});
};
This will update your leftOffset in the scope. Here is a Plunker.
It might be helpful to better understand how Angular does two-way data binding. This blog post on how apply works, and why one would be motivated to use it, is pretty good.
In summary, for your changes to $scope.rectangleOne:
You can call $scope.$digest() every time you make a simple change like this. You need to do this so Angular knows to check if your bound data got updated.
Alternatively, you can use $scope.$apply, make the changes to $scope.rectangleOne inside a callback to $apply. It's doing the same thing, $apply ends up calling $digest() indirectly.
In code:
$scope.$apply(function() {
$scope.rectangleOne.leftOffset = '12345';
});
Hope that helps solve your problem, and add a bit of understanding to what's happening behind the scenes!

Angular strap tooltip visible by default

I using http://mgcrea.github.io/angular-strap/#/tooltips#tooltips
and i can't use Scope methods ($show(), $hide()). Help me please. How i can use this methods?
I have input in ng-repeat
<div ng-repeat="item in data.queue" >
<input type="text" maxlength="40" bs-tooltip data-animation="am-flip-x" data-title="{{item.file.tooltip_title}}">
<div>
And i need to set visible tooltips if item.file.flag=== true, and then hide tooltip of beyond the 5 second.
To get show() and hide() methods you gotta do everything on javascript side. Something like this:
markup
<div id="div1">some</div>
directive
app.directive('someThing', ['$tooltip', '$timeout', function($tooltip, $timeout){
return {
link: function($scope){
$scope.someFunction = function (item){
$timeout(function(){
var target = angular.element(document.getElementById('div1'));
var myTooltip = $tooltip(target, { title:'tip!!', trigger:'manual', placement:'top'});
myTooltip.$promise.then(function() { myTooltip.show(); });
$timeout(function(){
myTooltip.$promise.then(function() { myTooltip.hide(); });
}, 4000);
}, 1500);
};
}
};
}]);
The Angular way of solving your problem is using, for instance, data-bs-show="item.file.flag".
It will show your tooltip while item.file.flag == true.
The bsShow attribute expects a boolean value, so if you need to hide after 5 seconds, you might have another flag and set it to false after this time using $timeout.
It is possible to use $show()/$hide() but it's tricky and ugly so I'd avoid that if possible.

$watch on clientWidth isn't working

Inside of my directive I have this and it works only in the beginning, and whenever I resize later it never fires.
scope.$watch ->
cw: element[0].clientWidth
,(newValue, oldValue)->
if newValue.cw isnt oldValue.cw
console.log "changed"
,true
Your function looks right to me, but it's important to note that it won't fire on resize unless you manually trigger a digest on the resize event.
Without this, angular doesn't realise there's been an event that should trigger a digest, and so none happen.
Try adding this (remember to inject $window):
angular.element($window).bind('resize', ()->
scope.$apply();
)
Just like Jason Goemaat said, its because Watches are only checked on a $digest cycle
Depending on how the way your element is resized maybe this example may help you.
Here is a menu that expands it self when pressed on the arrow.
<div class="menu" ng-class="{'expanded' : main.expanded}">
<div class="menu-handler" ng-click="main.expanded = !main.expanded">
</div>
</div>
The menu is expanded by a ng-click that makes a change on the scope, in this case its a boolean var that acts as a flag. As the opening of the menu is made throught the change in the scope it calls the $digest cycle iterating through all $watch.
scope.$watch(function() {
return element[0].clientWidth;
}, function(oldValue, newValue) {
console.log(oldValue, newValue);
});
You can view the full example in this JSfiddle
https://jsfiddle.net/owenbcal/zf17s0mL/
Hope i was helpfull.
the way I know about watching this kind of values is making a function that is fired once the value changes so then I watch that function :
in the service:
this.getDataOut = function () {
return self.dataOut;
};
in the controller:
$scope.$watch(dataService.getDataOut, function() {
$scope.dataOut = dataService.dataOut;
});

Checkbox list breaks, why? And optimal Angularjs way?

I don't understand this, but I suspect I'm doing something wrong, or a non-angularjs way.
I have a checkbox list inside ng-repeat. It controller loads the list from a JSON. Pretty straightforward really. I'm then using a directive (car-select) on each of the resulting checkboxes. This directive calls a function inside the main $scope (selectBrand()). This cycles through the selected checkboxes, and if checked==true, add to $scope.brand. I've added a textbox so that $scope.brand fills it, and i've set it to required so that it fires the built in validation e.g:
HTML:
<div ng-repeat="v in viewModel">
<label class="checkbox">
<input type="checkbox" ng-model="v.c" ng-checked="v.c" />{{v.n}}
</label>
</div>
<input type="text" name="brands" ng-model="brands" car-select required/> <br>
JS:
$scope.selectBrand = function() {
var selectedBrands = [];
angular.forEach($scope.viewModel, function(v){
if (v.c)
selectedBrands.push(v.v);
})
if (selectedBrands.length > 0)
$scope.brands = selectedBrands;
else
$scope.brands = null;
}
DIRECTIVE:
app.directive('carSelect', function() {
return function(scope, element) {
element.bind('change', function() {
scope.selectBrand();
})
}
});
Here's the weird part which I don't understand. It took a while to figure out that this particular line was making this whole thing work. If I add the following in the page, everything works great. But if i remove it, the whole thing breaks. WHY?!
<div>{{selectBrand()}}</div>
It's like the whole thing doesn't bind unless the above is called in the HTML. It's called in the directive, and I've tried putting that call inside the clickButton() function, but eventually it breaks. Either way, the live update of the textbox seems to fail if the above is removed. I'd love to get a good explanation of how I'm doing something wrong and how I could fix it :)
PLUNKER:
http://plnkr.co/edit/4QISKcq7YYH678YLsTTF?p=preview
Ok, i create fork ;-)
update variable with only data checked
your model :
{"cars":
[
{"v":"m","n":"Mini","c":false},
{"v":"c","n":"Corvette","c":true},
{"v":"b","n":"BMW","c":true},
{"v":"l","n":"Lamborghini","c":true},
{"v":"f","n":"Ferrari","c":false}
]
}
you want only checked :
$scope.brands = $filter('filter')($scope.viewModel, {c: true});
when model change you want to update your variable so use watch in controller
$scope.$watch('viewModel', function(newval, oldval){
if (oldval != newval)
{
$scope.brands = $filter('filter')($scope.viewModel, {c: true});
}
},true
);
});
see http://plnkr.co/edit/PnABre?p=preview

AngularJS ng-keydown directive only working for <input> context?

I am pretty new to AngularJS but found it quite to my liking so far. For my current project I need hotkey functionality and was happy to see that it is supported since the 1.1.2 release.
The ng-keydown directive (http://code.angularjs.org/1.1.3/docs/api/ng.directive:ngKeydown) works as expected for input types but fails me for any other context like div etc. which seems odd given that the documentation says otherwise.
Here is an minimal example (http://jsfiddle.net/TdXWW/12/) of the working respectively the not working:
<input ng-keydown="keypress($event)">
<div ng-keydown="keypress($event)">
NOTE: I know this could be handled with plain jQuery (http://www.mkyong.com/jquery/how-to-check-if-an-enter-key-is-pressed-with-jquery/) but I much prefer to understand how to deal with it in AngularJS.
I was having the same problem and was able to fix it by following this simple tip provided in this comment: https://stackoverflow.com/a/1718035/80264
You need to give the div a tabindex so it can receive focus.
<div id="testdiv" tabindex="0"></div>
Thanks! To wrap this up I got this working by, injecting $document into my directive, then:
MyApp.directive('myDirective', function($document) {
return {
...
$document.keydown(function(e){
console.log(e)
})
}
This was the way I got it working in the end.
Add ng-app to the html element and ng-keyup and ng-keydown to the body element:
<html ng-app="myApp" ng-controller="MainCtrl">
.....
<body ng-keydown="keyPress($event);" ng-keyup="keyRelease($event);">
Then the funcitons in my controller deal with the event calling event.which to get the key code (in my implementation I set a var to the rootScope but you could also broadcast to other controllers)
$scope.keyPress = function(eve) {
if (eve.which === 16) { // shift
// $rootScope.$broadcast('doShift');
$rootScope.shiftOn = true;
};
};
The comment by charlietfl cleared things up and binding the event to $(document) worked as expected! Take away message: The AngularJS documentation is not really exhaustive, i.e. demands background knowledge.
angular.module('app').directive('executeOnEnter', function () {
return {
restrict: 'A',
link: function (scope, el, attrs, $rootScope) {
$('body').on('keypress', function (evt) {
if (evt.keyCode === 13) {
el.trigger('click', function () {
});
}
})
},
controller: function ($rootScope) {
function removeEvent() {
$("body").unbind("keypress");
}
$rootScope.$on('$stateChangeStart', removeEvent);
}
}
})
it worker fine for me, just add tabindex attribute. make sure that ng-keydown contains correct angularjs expression
<div ng-keydown="keypress($event)" tabindex="0">
$scope.keypress = function(ev) {
console.log('keyprez', ev);
}

Resources