How to get the uib-popover to open or close when the focus of the input field changes - angularjs

I have a input field that has the uib-popover control on it. I have followed the documentation on how to get the directive to open but I have noticed some discrepancies in the documentation as well as examples on plnker and SO questions here.
Within my hmtl I have the inputs set as follows:
<div class="form-group col-xs-6 col-sm-6 col-md-6 col-lg-6">
<label>Password</label><input type="{{user.inputType}}" ng-blur="user.validatePassword(user.newUser.password, user.newUser.confirmPassword)" placeholder="Enter Password" id="password" required class="form-control" ng-model="user.newUser.password" uib-popover-template="'myPopoverTemplate.html'" uib-popover-trigger="'focus'"/>
</div>
<div class="form-group col-xs-6 col-sm-6 col-md-6 col-lg-6">
<label>Confirm Password</label>
<input type="{{user.inputType}}" ng-keyup="user.validatePassword(user.newUser.password, user.newUser.confirmPassword)" placeholder="Confirm Password" id="confirmPassword" required class="form-control" ng-model="user.newUser.confirmPassword"/>
<span style="color: red">{{user.message}}</span>
</div>
Most examples as well as the SO questions on here are using an older library as attributes are not prefaced with uib-*.
This code/directive currently works and renders but it only work or appears when clicking in the field and then clicking in the same field to close the popover. I have tried both the focus trigger and the oustsideClick trigger. Both have the same result of not rendering or closing the popover unless clicking in the field.
versions of the frameworks used are:
angularjs 1.5.8
ui-bootstrap 1.3.3
Changing the trigger to match earlier examples were popover-trigger is used vs. uib-popover-trigger is used disables the popover
I have created a working plunker that demonstrates what is happening.
Any suggestions on what I am missing or what I need to change.
Thanks in advance

According to tooltip.js description, in order to set a custom trigger,
it needs to be specified via trigger option passed to the $tooltipProvider.options method. In your case for focus trigger it will be:
app.config(['$uibTooltipProvider', function ($uibTooltipProvider) {
$uibTooltipProvider.options({ trigger: 'focus' });
}]);
Updated plunker that shows how to trigger tooltip on focus handler.

There's a problem of your code, please modify like below:
app.js:
(function() {
var app = angular.module('app', ['ui.bootstrap']);
app.controller('main',[ '$scope', main]);
function main($scope)
{
vm = this;
vm.message = 'hello';
vm.dynamicPopover = {
content: 'Hello, World!',
templateUrl: 'myPopoverTemplate.html',
title: 'Title'
};
}
}());
index.html
<input class="form-control" uib-popover-template="vm.dynamicPopover.templateUrl" popover-trigger="focus"/>
Actually, you can not just pass the template's id to the uib-popover-template attribute, you need to create an object to map it waited to pass.

Related

Angular js ng messages show error on init

In my project I have angularjs 1.5.10 and ng-messages 1.5.10. I use it in simple form:
<form class="form-horizontal" ng-submit="createBooking()" role="form" name="createBookingForm" novalidate>
<div class="form-group">
<label for="payment_details_last_name" class="col-sm-3 control-label">Last name</label>
<div class="col-sm-6">
<input type="text"
id="payment_details_last_name"
name="payment_details_last_name"
class="form-control"
ng-model="payment_details.last_name"
ng-required="true"
ng-maxlength="30" />
<div ng-messages="createBookingForm.payment_details_last_name.$error" role="alert">
<div ng-message="required">This field is required</div>
<div ng-message="maxlength">Your field is too long</div>
</div>
</div>
<div class="col-sm-3"></div>
</div>
</form>
In controller:
$scope.members = [{
'first_name': '',
'last_name': '',
'email': '',
'phone_number': '',
'date_of_birth': '',
}];
And on initial I always see error This field is required. I tried to create empty object in controller:
$scope.createBookingForm = {};
I also show form after initialized <div ng-if="initialized">
Nothing is working. Project using angular-seed skeleton
I saw dirty hacks like if $touched else, but I want to understand what is wrong...
Nothing is wrong about it, check out the sample in the official guide. They have required error shown by default. It seems wrong for the first glance, but this is the only correct way to handle such a case.
So basically, ng-messages does exactly what docs says:
ngMessages is a directive that is designed to show and hide messages
based on the state of a key/value object that it listens on.
the directive works in a real time and shows errors for current input state, that makes sense.
So if you want no messages to be shown by default, you should use some of approaches, discussed hundred of times
How to make ngMessage for required fields only show when dirty or submitting a form?
Angular : ng-message validation on submit click
AngularJS: Hiding ng-message until hitting the form-submit button
AngularJS 1.5.6 reset form & ng-messages
If you need some other improved behavior - there is no quick solution at the moment, you have to come up with your own validation engine that fit your needs.

Get pristine value in Angular controller

I need to be able to see in the Angular controller if the datepicker is pristine or not. Tried all sorts of things including sending the pristine value in a method but cannot get this value. Below is the view code:
<form name="myForm">
<!-- Datepicker From -->
<div class="small-6 medium-5 large-2 columns" ng-if="vm.subViewActive">
<div class="input-group">
<input name="valuationDatePickerFrom" ng-model="name" type="text" class="datepicker" id="valuationDatePickerFrom" placeholder="DD/MM/YYYY" pikaday="vm.datePickerFrom" on-select="vm.selectStartDate(pikaday)" year-range="{{ vm.yearRange }}" >
<div class="input-group-addon">
<label for="valuationDatePickerFrom" class="postfix">
<i class="fa fa-calendar"></i> From
</label>
</div>
</div>
</div>
</form>
and then I also tried :
var isPristine = $scope.myForm.valuationDatePickerFrom.$pristine;
console.log(isPristine);
in my controller but cannot get the pristine value. Read lots of posts here but mainly to do with CSS classes and front-end control or setting the pristine state from the backend not getting or checking the pristine state.
Thanks anybody that can help.
You are using:
var isPristine = $scope.myForm.valuationDatePickerFrom.$pristine;
but your form's name is not myForm.
Change <input name="name"... <input name="valuationDatePickerFrom"...
Then you can use:
var isPristine = $scope.userForm.valuationDatePickerFrom.$pristine;
Also, the controller is getting called before the view is created, so no myForm exists at the time the controller runs. Try adding a $timeout like so:
$timeout(function() {
var isPristine = $scope.userForm.valuationDatePickerFrom.$pristine;
console.log(isPristine);
}, 100);
plunkr
The above solution only works on page load, but you need to know this value when the page is being used. Instead pass the value to the controller when an action happens:
<form name="myForm">
<input type="text" name="valuationDatePickerFrom" ng-model="valuationDatePicker" ng-blur="alerty(myForm.$pristine)">
</form>
.controller('MainController', function($scope) {
$scope.alerty = function(isPristine){
alert('isPristine: ' + isPristine);
};
https://plnkr.co/edit/f0EWvYmoXCn8UOH3QCfE?p=preview

Angular - Watching a form whether its $dirty - performance

In my Angular app, I'm setting the placeholders in my form through some code in the controller (showing particular text for particular times of day).
When a user begins typing into any field of that form, I want all placeholders to be cleared.
To do this I understand I need to use $dirty using $watch
$scope.$watch('myForm.$dirty', function() {
//clear the placeholders
}, true);
My question is watch quite performance intensive in this situation or is there a more optimised way?
Thanks.
If you use $dirty and $watch it will work but it will clear all placeholders before you begins type or on controller load.
So, you can try this its work for me.
<div ng-controller="Ctrl">
<input type="text" ng-model="name1" ng-change="change()" placeholder={{placeholder1}}>
<input type="text" ng-model="name2" ng-change="change()" placeholder={{placeholder2}}>
<input type="text" ng-model="name3" ng-change="change()" placeholder={{placeholder3}}>
</div>
function Ctrl($scope) {
$scope.placeholder1="name";
$scope.placeholder2="city";
$scope.placeholder3="address";
$scope.change=function() {
$scope.placeholder1="";
$scope.placeholder2="";
$scope.placeholder3="";
};
}

Form validation with modals in Angular

I have a form inside a modal pop up. I am trying to run form validation on the inputs after the user attempts to submit the form. So far, I'm struggling to make things work.
In my view, I have the following (sorry if there are any syntax errors, I'm converting this from jade on the fly):
<script type="text/ng-template", id="modalVideoNew">
<div class="ngdialog-message">
<form class="form-horizontal" ng-submit="submitForm()" novalidate name="newVideoForm">
...
<div class="form-group">
<label> Title </label>
<div class="col-sm-8">
<input type="text" name="title", required='', ng-model="newVideoForm.title">
<span class="text-danger" ng-show="validateInput('newVideoForm.title', 'required')"> This field is required</span>
</div>
</div>
</div>
</script>
And then in my controller, where I'm calling the ng-dialog pop up, I have this:
$scope.newVideo = function() {
ngDialog.openConfirm({
template: 'modalVideoNew',
className: 'ngdialog-theme-default',
scope: $scope
}).then(function() {
$scope.validateInput = function(name, type) {
var input = $scope.newVideoForm[name];
return (input.$dirty || $scope.submitted) && input.$error[type];
};
var newVideo = $scope.newVideoForm;
...
Right now, I am still able to submit the form, but once I open it back up I see the 'This field is required' error message. Also, the input is pre-filled with [object, Object] instead of an empty text input box.
A way of cleaning your model would work with using a model var that belongs to your parent controller and cleaning it in the callback. Check out how the template has attached your parent controller's var FormData.
Check this out
So about your validation, what I would recommend you is to have your own controller in it, no matter how much code it will have. It helps you keeping concepts of modularization and a better control over your scopes. This way will also facilitate a lot when validating.

angular.element is not working in tabset directive of angular js

I'm using tabset directive of angular js and using twitter bootstrap slider in tab,
My slidestop event is not calling but it's working well outside tab.
I know that tabset directive have its own scope , but dont know solution of following problem:-
<tabset class="tab-container">
<tab heading="tab1">
<div class="form-group">
<label>any Level</label>
<div class="input-group w-md">
<input id="slider" ui-jq="slider" ui-options="{min: 0,max: 10,step: 1,value: {{any_level}}}"
class="slider slider-horizontal form-control" type="text"
ng-model="any_level"> {{any_level}}
</div>
</div>
</tab>
</tabset>
controller code
......
angular.element("#slider").on('slideStop', function(data){
alert('asdasd');
})
problem is - alert is not coming when slider inside tab,alert is comming when slider outside tab
i am using this slider
Thanks
i have solved using ui-event directive to fire slidestop event
Html Code
<input id="slider"
ui-event="{slideStop: 'alertChange($event)'}" ui-jq="slider"
ui-options="{min: 0,max: 10,step: 1,value: {{any_level}}}"
class="slider slider-horizontal form-control" type="text" ng-model="any_level">
{{any_level}}
Controller Code
$scope.alertChange = function(data){
console.log(data.value); // i can get slider value on slidestop
}
Just don't use angular.element in an angular app.
EDIT : This isn't really working with ui-slider. Till ui-slider is work in progress i just woudn't use it.
Add this to your input :
ng-change="alertChange()"
And this to your controller :
$scope.alertChange = function(){
alert('hi');
}
What wasn't working ? In most of the case an angular.element will try to bind your even to the element too early. Your DOM "#slider" element isn't probably loaded when your try to bind.
EDIT An alternative :
First, after paying more attention i wouldn't recommend this slider at all.
This is actually a work in progress and isn't really reliable.
I made you an exemple of a html slider with binding in this plunker
You slider looks like this :
<input id="slider"
ng-model-options="{ debounce: 100 }"
min="0"
max="100"
ng-init="any_level = 0"
ng-change="alertChange()"
type="range"
ng-model="any_level">
This will update the model each time the value will not change for 100miliseconds. You need this to avoid firing too much ng-change function.
In your javascript you just need to declare your function
$scope.alertChange = function(){
console.log("I changed !");
//or anything else you want to do
}
I know this is not a solution but an alternative. It's not sexy as the other slider, but at least it works.
Hope it helped you.
The slider you are using has an example demonstrating how to do this. Take a look at box "12" on this page: http://angular-ui.github.io/ui-slider/demo/demo.html
In your controller you can add the following:
$scope.slider = {
'options': {
stop: function (event, ui) { $log.info('Slider stop'); };
}
And your HTML you must reference slider.options so your callback is fired:
<div ui-slider="slider.options"
min="0" max="50" ng-model="any_level"></div>

Resources