bootstrap-timepicker directive not working inside ng-repeat - angularjs

Plunker demo
I'm trying to create an arbitrary number of timepicker, when hardcoded they work fine but it stops working when I put them into an ng-repeat. Is there a way to fix this?

I just updated my Plunker with a better solution.
Tiago answered AngularJS ng-repeat finish event with a great directive that will solve your issue without using the $timeout
Here is a copy of the directive:
app.directive('myRepeatDirective', function() {
return function(scope, element, attrs) {
if (scope.$last) {
$('.bootstrap-timepicker').timepicker();
}
};
});
HTML:
<li ng-repeat="list in lists" my-repeat-directive>
{{list.name}}
<div class="input-append">
<input type="text" class="bootstrap-timepicker">
<span class="add-on"><i class="icon-time"></i></span>
</div>
</li>
This is better because if you repeater requires data from an ajax request than your timeout could have to be altered and cause an ugly user experience.
Tiago's method seems to handle it best, in my opinion, you might also want to give him an upvote :)

I solved this using the ng-init because solution provided by Asok was not working for me. I also didn't want to use $scope
AngularCode
angular.module('MyApp', [])
.controller('MyController', MyController);
function MyController($http) {
// your code here...
jd.InitTime = function () {
$('.bootstrap-timepicker').timepicker();
};
};
HTML
<div data-ng-app="MyApp" data-ng-controller="MyController as mc">
<li ng-repeat="list in mc.lists">
{{list.name}}
<div class="input-append">
<input type="text" class="bootstrap-timepicker" ng-init="mc.InitTime();">
<span class="add-on"><i class="icon-time"></i></span>
</div>
</li>
</div>

Related

Trigger ng-submit on ng-click

I am following this answer (and this fiddle) on how to accomplish this.
View:
<section>
<form style="display: none" id="addFriendForm" name="vm.form.addFriendForm" class="form-horizontal" submit-on="submitAddFriendForm" ng-submit="vm.save(vm.form.addFriendForm.$valid)" novalidate>
<input ng-model="vm.userInput" required>
</form>
<div class="list-group">
<a ng-repeat="user in vm.users" ng-click="vm.triggerSubmit(user)" class="list-group-item">
...
</a>
</div>
</section>
Directive:
function submitOn() {
return {
link: function postLink(scope, element, attrs) {
scope.$on(attrs.submitOn, function() {
setTimeout(function() {
// Error:
element.trigger('submit');
});
});
}
};
}
Controller: (triggerSubmit)
// Trigger submit of the form
function triggerSubmit(user) {
vm.userInput = user;
$scope.$broadcast('submitAddFriendForm');
}
When walking through this, I get the error:
TypeError: element.trigger is not a function
...on the line highlighted in the directive. Looking at docs, this seems correct. What's the reason for it failing?
ANSWER:
(if a jQuery answer is wanted, look at the answer below)
A pure angular way of doing it is:
angular.element(element).triggerHandler('submit');
Looks like trigger is not a part of JQLite which ships with angular.
You might have to load JQuery before loading angular.
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
OR
As part of your build pipeline (grunt/gulp/webpack etc)
See the other answer for a jQuery approach. For a pure angular approach I used:
angular.element(element).triggerHandler('submit');

Angularjs compile a directive inside ng-repeat with isolated scope

I have a directive in the form of a dropdown, pretty simple. The user can click a button to add as many as they need to in a ul, make their selections, and save it off. This is all inside of several ng-repeats.
I'm having trouble mastering the scope. As I expected, this works:
<div ng-repeat="group in groups" question-group="group" class="question-group">
<div ng-repeat="question in questions">
<ul>
<li ng-repeat="case in question.cases"></li>
<li><new-case group='group'></new-case></li>
</ul>
</div>
</div>
When I say "works", I mean that group is properly scoped (the data of the entire group is necessary for the resulting input).
When I switch it to "click to add":
<div ng-repeat="group in groups" question-group="group" class="question-group">
<div ng-repeat="question in questions">
<ul>
<li ng-repeat="case in question.cases"></li>
<li>add case</li>
</ul>
</div>
</div>
group is undefined in the scope. Here is my createNewCase function:
function createNewCase($event) {
var thisLi = angular.element($event.target).closest('li');
var listItem = $compile('<li><new-case group=\'group\'></new-case></li>');
var html = listItem($scope);
thisLi.before(html);
}
$scope.createNewCase = createNewCase;
And the newCase directive:
angular.module('groups.directives.newCaseDirective', [])
.directive('newCase', ['$window', function() {
return {
restrict: 'EA',
scope: { group: '=' },
templateUrl: 'groups/views/newcase.tpl.html'
};
}]);
I've been reading for days and I've tried a few other derivatives but I'm ultimately just not getting it. Help is greatly appreciated.
Thanks!
The issue is that group is created by ng-repeat and is only available in child scopes of ng-repeat.
Each repeated element is in it's own child scope. So your directive version works but your other one doesn't because the controller doesn't see those child scopes.
You would have to pass group as argument of the function if you want to access it in controller
<a href="#" ng-click="createNewCase($event, group)">

AngularJS invoke Controller function

sorry for the rather basic question but I am really a beginner developing in AngularJS.
So I have a conteoller like this (like explaned here: https://github.com/johnpapa/angular-styleguide):
(function() {
'use strict';
angular
.module('project.management')
.controller('ManagementController', ManagementController);
function ManagementController() {
var vm = this;
vm.getUsersBySearchString= getUsersBySearchString;
////////////
function getUsersBySearchString(searchString) {
alert('get User By searchstring: ' + searchString);
}
};
})();
Now I have a HTML fragment in my template and I really don't know how to invoke function getUsersBySearchString(searchString). I have tried this one:
<div ng-controller="vm">
<form class="well form-search">
<label>Usersuche:</label>
<input type="text" ng-model="term" class="input-medium search-query" placeholder="Username">
<button type="submit" class="btn" ng-click="getUsersBySearchStringgetUsersBySearchString()">Suchen</button>
</form>
<pre ng-model="result">
{{result}}
</pre>
</div>
but I don't know what to put here
<div ng-controller="vm">
and how to invoke the method.
Thanks a lot for help!
<div ng-controller="vm">
That is incorrect. You have no controller named "vm". Your controller is named ManagementController.
The syntax for your use-case is
<div ng-controller="ManagementController as vm">
And to invoke the function, you would use
ng-click="vm.getUsersBySearchString(term)"
Note that the alias you choose in the HTML has no relationship with the alias you chose for thisin the controller code. You might very well use
<div ng-controller="ManagementController as managementCtrl">
and
ng-click="managementCtrl.getUsersBySearchString(term)"

Live search in AngularJS: updating the results

I want a live search: the results are queried from web api and updated as the user types.
The problem is that the list flickers and the "No results" text appears for a fraction of second, even if the list of results stays the same. I guess I need to remove and add items with special code to avoid this, calculating differences between arrays, etc.
Is there a simpler way to avoid this flicker at least, and probably to have possibility to animate the changes?
It looks like this now:
The html part is:
<div class="list-group">
<a ng-repeat="test in tests track by test.id | orderBy: '-id'" ng-href="#/test/{{test.id}}" class="list-group-item">
<h4 class="list-group-item-heading">{{test.name}}</h4>
{{test.description}}
</a>
</div>
<div ng-show="!tests.length" class="panel panel-danger">
<div class="panel-body">
No tests found.
</div>
<div class="panel-footer">Try a different search or clear the text to view new tests.</div>
</div>
And the controller:
testerControllers.controller('TestSearchListCtrl', ['$scope', 'TestSearch',
function($scope, TestSearch) {
$scope.tests = TestSearch.query();
$scope.$watch('search', function() {
$scope.tests = TestSearch.query({'q':$scope.search});
});
}]);
You should use ng-animate module to get the classes you need for smooth animation. For each ng-repeat item that's moved, added, or removed - angular will add specific classes. Then you can style those classes via CSS or JS so they don’t flicker.
An alternative way of doing what you require is to use the angular-ui bootstrap Typeahead component (check at the bottom of the post). It has a type-ahead-wait property in milliseconds and also a template url for customising it.
<div ng-app>
<div ng-controller="MyController">
<input type="search" ng-model="search" placeholder="Search...">
<button ng-click="fun()">search</button>
<ul>
<li ng-repeat="name in names">{{ name }}</li>
</ul>
<p>Tips: Try searching for <code>ann</code> or <code>lol</code>
</p>
</div>
</div>
function MyController($scope, $filter) {
$scope.names = [
'Lolita Dipietro',
'Annice Guernsey',
'Gerri Rall',
'Ginette Pinales',
'Lon Rondon',
'Jennine Marcos',
'Roxann Hooser',
'Brendon Loth',
'Ilda Bogdan',
'Jani Fan',
'Grace Soller',
'Everette Costantino',
'Andy Hume',
'Omar Davie',
'Jerrica Hillery',
'Charline Cogar',
'Melda Diorio',
'Rita Abbott',
'Setsuko Minger',
'Aretha Paige'];
$scope.fun = function () {
console.log($scope.search);
$scope.names = $filter('filter')($scope.names, $scope.search);
};
}

AngularUI ui-keypress for any button?

Alright so, what I need is a way to forward keypress (or keydown, whatever) event that occurred on textarea element, and what I've tried to do is this:
<div id="wrapper" ng-controller="MyTestCtrl">
<div id="text" ng-click="DivClick()">
<ul>
<li ng-repeat="item in items">
<textarea ng-click="InnerClick()" ui-keypress="TextKeypress()" autofocus></textarea>
</li>
</ul>
</div>
</div>
But it seems to be acting funny and I want to avoid using any particular key-code since I need it to updates that textarea's height every time a user types something in it (which is what TextKeypress functions is doing).
You could use uiEvent: <textarea ui-event=" { keypress: 'whatever($event)' } ">
UPDATE:
The core now include ng-keypress too! (no idea which version)
Alright, I've overcome this by creating a custom directive that suits my needs and I've bound that directive to the element with 'keypress'. Something like this:
.directive('mydKeypress', function(){
return function(scope, elm, attrs){
elm.bind('keypress', function(e){
//Whatever code;
alert('it bloody works!');
});
};
});

Resources