Angular Material Dialog Mobile Keyboard Issue - mobile

The issue I'm seeing occurs on a mobile device, specifically I'm using an iPhone 6s Plus with iOS 10.0.
http://codepen.io/AstroDroid/pen/beqjoL
class AppController {
status = '';
customFullscreen;
constructor(private $scope, private $mdDialog, private $mdMedia, private $mdToast) {
this.customFullscreen = this.$mdMedia('xs') || this.$mdMedia('sm');
}
showDialog(event) {
var useFullScreen = (this.$mdMedia('sm') || this.$mdMedia('xs')) && this.customFullscreen;
this.$mdDialog.show({
controller: LoginDialogController,
controllerAs: 'dialog',
templateUrl: 'login-dialog.template.html',
parent: angular.element(document.body),
targetEvent: event,
clickOutsideToClose: true,
fullscreen: useFullScreen
})
.then(credentials => this.showToast(`Thanks for logging in, ${credentials.username}.`),
() => this.showToast('You canceled the login.'));
this.$scope.$watch(() => this.$mdMedia('xs') || this.$mdMedia('sm'),
wantsFullScreen => this.customFullscreen = wantsFullScreen === true);
}
showToast(content: string) {
this.$mdToast.show(
this.$mdToast.simple()
.content(content)
.position('top right')
.hideDelay(3000)
);
}
}
class LoginDialogController {
username: string;
password: string;
constructor(private $mdDialog) { }
hide() {
this.$mdDialog.hide();
}
close() {
this.$mdDialog.cancel();
}
login() {
this.$mdDialog.hide({username: this.username, password: this.password});
}
}
function config($mdThemingProvider) {
$mdThemingProvider.theme('default')
.primaryPalette('blue')
.accentPalette('orange');
$mdThemingProvider.theme('input', 'default')
.primaryPalette('grey')
}
angular
.module('app', ['ngMaterial', 'ngMessages', 'material.svgAssetsCache'])
.controller('AppController', AppController)
.config(config);
.dialogdemoBasicUsage #popupContainer {
position: relative;
}
#login-dialog {
max-width: 90%;
width: 500px;
}
<div ng-app="app" ng-controller="AppController as login" class="md-padding dialogdemoBasicUsage" id="popupContainer" ng-cloak>
<div class="dialog-demo-content" layout="row" layout-wrap layout-margin layout-align="center">
<md-button class="md-primary md-raised" ng-click="login.showDialog($event)">
Login
</md-button>
</div>
<div hide-gt-sm layout="row" layout-align="center center" flex>
<md-checkbox ng-model="login.customFullscreen" aria-label="Fullscreen Custom Dialog">Force Custom Dialog Fullscreen</md-checkbox>
</div>
<div ng-if="login.status" id="status">
<b layout="row" layout-align="center center" class="md-padding">
{{login.status}}
</b>
</div>
<script type="text/ng-template" id="login-dialog.template.html">
<md-dialog id="login-dialog" aria-label="Login" ng-cloak>
<form name="loginForm" ng-submit="dialog.login()">
<md-toolbar>
<div class="md-toolbar-tools">
<h2>Log In</h2>
<span flex></span>
<md-button class="md-icon-button" ng-click="dialog.close()">
<md-icon md-svg-src="img/icons/ic_close_24px.svg" aria-label="Close dialog"></md-icon>
</md-button>
</div>
</md-toolbar>
<md-dialog-content>
<div class="md-dialog-content">
<md-input-container class="md-block">
<label>Username</label>
<input name="username" ng-model="dialog.username" md-autofocus required />
</md-input-container>
<md-input-container class="md-block">
<label>Password</label>
<input type="password" name="password" ng-model="dialog.password" required />
</md-input-container>
</div>
</md-dialog-content>
<md-dialog-actions layout="row">
Forgot Password?
<span flex></span>
<md-button type="submit" ng-disabled="loginForm.$invalid" class="md-raised md-primary">Login</md-button>
</md-dialog-actions>
</form>
</md-dialog>
</script>
</div>
Sorry for the code, it wouldn't let me post without it. A complete, working example is already in the pen, so this is not bad, nor do I feel bad, nor should I.
When I bring up the modal and focus one of the text inputs and close the modal, either by the 'X' or by filling out the fields and tapping 'Login', when the modal is dismissed, the keyboard remains on the screen. When I tap 'Done' in the keyboard, it is dismissed, but comes back anytime I tap anywhere else on the screen. The only way I can keep it away is if I make sure I tap 'Done' before either closing the dialog with the 'X' or tapping 'Login'.
I am guessing the issue is with how Angular Material 'hides' the dialog, the onscreen keyboard still thinks the text inputs are valid.
Does anyone know of a workaround, or if this pen is not using $mdDialog correctly?

A workaround I have found is to make sure the inputs are blurred as the dialog is closed. I did this by adding
this.$document[0].activeElement.blur();
to my dialog.login() method.

Related

Disabling Button in Master Page using AngularJS

I have the following Master Page:
<body ng-app="app" ng-controller="controller" ng-cloak>
<div class="header" ng-bind="header"></div>
<div class="content">
<!-- This content will switch -->
<ui-view></ui-view>
</div>
<div class="footer" ng-show="showFooter">
<md-button class="md-raised md-primary" ng-click="cancel()">Cancel</md-button>
<md-button class="md-raised md-primary" ng-click="ok()">OK</md-button>
</div>
And the following Add Contact page which goes in <ui-view> tags:
<form name="form">
<button class="round-button"></button><br />
<md-input-container>
<input name="name" ng-model="name" placeholder="Name" minlength="3">
<div ng-messages="form.name.$error" ng-show="form.name.$dirty">
<div ng-message="required">This is required.</div>
<div ng-message="minlength">Name has to be at least 3 characters long.</div>
</div>
</md-input-container>
<br />
<md-input-container>
<label>Phone</label>
<input name="phone" ng-model="phone" placeholder="Phone" ng-pattern="/^[0]{1}[5]{1}[0-9]{1}[0-9]{7}$/">
<div ng-messages="form.phone.$error" ng-show="form.phone.$dirty">
<div ng-message="required">This is required.</div>
<div ng-message="pattern">Please enter a valid phone number.</div>
</div>
</md-input-container>
<br />
<md-input-container>
<label>Mail</label>
<input name="mail" ng-model="mail" placeholder="Mail" ng-pattern="/^[\w\-\.\+]+\#[a-zA-Z0-9\.\-]+\.[a-zA-z0-9]{2,4}$/">
<div ng-messages="form.mail.$error" ng-show="form.mail.$dirty">
<div ng-message="pattern">Please enter a valid mail.</div>
</div>
</md-input-container>
<br />
</form>
My Controller for Add Contact page is as follows:
controller: function ($scope, $state, $rootScope,$http) {
$rootScope.cancel = function () {
$state.go("contacts");
};
$rootScope.ok = function () {
var contactInfo = {
name: $scope.name,
phone: $scope.phone,
mail: $scope.mail,
address: $scope.address
};
$http.post("/api/Contact", contactInfo)
.then(function (res) {
alert("contact added successfully");
});
$state.go("contacts");
};
$rootScope.header = "Add Contact";
$rootScope.showFooter = true;
Before I call the web service using $http , I would like the OK button in the Master Page to be disabled until all fields in the form have been filled correctly.
Is there a way to achieve this goal?
You should be able to accomplish this by putting a ng-disabled directive on the button and have it check if the form is valid.
<md-button class="md-raised md-primary" ng-disabled="!form.$valid" ng-click="ok()">OK</md-button>

md dialog not working properly?

I'm new to angular material:
I want to show dialog for editing records in a table:
I referenced angular material and angular aria, used ngMaterial dependency and $mdDialog service.
I have a div containing all editing fields, the div visibility is set to hidden:
<div style="visibility: hidden">
<div class="md-dialog-container" id="taskEdit">
<md-dialog style="width:100%; height:100%" layout-padding>
<md-toolbar>
<div class="md-toolbar-tools">
<h2>Edit Task</h2>
<span flex></span>
</div>
</md-toolbar>
<ng-form name="TaskForm">
<div layout-gt-sm="row">
<md-input-container>
<label>Task Title</label>
<input name="TaskTitle" ng-model="task.title" required>
<div ng-messages="TaskForm.TaskTitle.$error">
<div ng-message="required">This is required</div>
</div>
</md-input-container>
<md-input-container class="md-block" flex-gt-sm>
<label>Description</label>
<textarea ng-model="task.description" md-maxlength="150" md-select-on-focus></textarea>
</md-input-container>
<md-input-container class="md-block">
<label>Due Date</label>
<md-datepicker style="margin-top: 2px;" ng-model="task.dueDate"></md-datepicker>
</md-input-container>
<md-input-container>
<label>Task Status</label>
<input name="TaskStatus" ng-model="task.status">
</md-input-container>
</div>
</ng-form>
<input class="btn btn-primary" style="width:15%" type="submit" ng-disabled="!TaskForm.$valid" ng-click="EditTask()" value="Submit" aria-label="submit" />
</md-dialog>
</div>
</div>
here's the showDialog function::
$scope.showDialog = function () {
$mdDialog.show({
controller: DialogController,
contentElement: '#taskEdit',
parent: angular.element(document.body),
clickOutsideToClose: true
});
};
function DialogController($scope, $mdDialog) {
$scope.hide = function () {
$mdDialog.hide();
};
$scope.cancel = function () {
$mdDialog.cancel();
};
}
but when I click the button, the dialog is not appearing properly, it lacks the animation and is rendered in the same layer as the parent page:
You need to refer the angular material css
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.0.4/angular-material.css">

ng-show and ng-hide with ng-clikc function in ng-repeat loop

I'm new to angular JS. I didn't know how to use ng-show and ng-hide with ng-click function in ng-repeat loop. Here is my code:
<div ng-repeat="listname in get_checklist track by $index">
<span ng-click="CKItemShowHide()"> Add Item </span>
<div ng-show ="CKItemIsVisible" ng-cloak class="labelBoardpopup memberBoardpopup" layout="row" layout-wrap>
<h3>Create Item</h3>
<div class="createBoardpopupform" layout="row">
<form flex>
<md-input-container class="md-block" flex-gt-sm>
<label>Item name</label>
<input ng-model="CKItem" ng-required="true">
</md-input-container>
<md-button class="md-raised md-primary">Add</md-button>
</form>
</div>
</div>
</div>
In controller i have code like this:
$scope.CKItemIsVisible = false;
$scope.CKItemShowHide = function () {
$scope.CKItemIsVisible = $scope.CKItemIsVisible ? false : true;
};
In this code when i click add item it will show and hide all div content at the same time. But i want to show individual content show and hide. If anyone can please help.
Instead of calling a method on ng-click, you can directly take a scope variable show in my example, and change it to true or false using !show
Since ng-repeat creates a new scope on every iteration, the show scope variable is always local to the current iteration.
Please check this code,
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.get_checklist = [
{
test: "test"
},
{
test: "test"
},
{
test: "test"
}
];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller="MyCtrl" ng-app="myApp">
<div ng-repeat="listname in get_checklist">
<span ng-click="show = !show"> Add Item </span>
<div ng-show ="show" ng-cloak class="labelBoardpopup memberBoardpopup" layout="row" layout-wrap>
<h3>Create Item</h3>
<div class="createBoardpopupform" layout="row">
<form flex>
<md-input-container class="md-block" flex-gt-sm>
<label>Item name</label>
<input ng-model="CKItem" ng-required="true">
</md-input-container>
<md-button class="md-raised md-primary">Add</md-button>
</form>
</div>
</div>
</div>
Please run this snippet
Here is the fiddle

get ng-model $resource in controller

I need to set the ng-model via controller by selecting one of the listed images in Dialog and insert the ng-model of the form to record it in json-server.
My resource is provide by json-server.
Is there any way to do this? Or there's no way .. or some other way?
Template:
<form class="form-horizontal" role="form" ng-submit="addItem($stateParams.section)" enctype="multipart/form-data">
<div layout="row" layout-wrap>
<div flex="75">
<md-card>
<md-card-content>
<h2>Adicionar novo Post</h2>
<md-input-container>
<label>Digite o título aqui</label>
<input ng-model="item.title">
</md-input-container>
<md-input-container>
<label>Introdução</label>
<input ng-model="item.subtitle">
</md-input-container>
<md-input-container>
<label>Link permanente</label>
<input ng-model="item.slug">
</md-input-container>
<text-angular ng-model="item.content"></text-angular>
<md-input-container>
<label>Resumo</label>
<input ng-model="item.excerpt">
</md-input-container>
</md-card-content>
</md-card>
</div>
<div flex="25">
<md-card>
<md-card-content>
<h2>Configurações do Post</h2>
<md-input-container ng-controller="PublishedControl">
<md-select name="situation" ng-model="item.situation" placeholder="Status do Post">
<md-option ng-repeat="pub in publisheds" ng-value="{{pub.id}}">{{pub.name}}</md-option>
</md-select>
</md-input-container>
<div layout layout-sm="column">
<md-input-container flex>
<label>Date</label>
<input type="date" ng-model="item.posted">
</md-input-container>
<md-input-container flex>
<label>Time</label>
<input type="time" ng-model="item.posted">
</md-input-container>
</div>
<md-card-footer layout="row" layout-sm="column" layout-align="center center" layout-wrap>
<md-button class="md-raised md-primary" type="submit">Salvar</md-button>
<md-button class="md-raised" ui-sref="listItems({section: $stateParams.section})">Cancelar</md-button>
</md-card-footer>
</md-card-content>
</md-card>
<md-card ng-if="categorias[0].cats">
<md-card-content>
<h2>Categorias</h2>
<div layout-padding>
<!-- <checkbox ng-repeat="cat in categorias[0].cats" value="{{cat.id}}" ng-checked="{{item.cats.indexOf(cat.id) > -1}}" ng-model="item.cats">{{cat.name}}</md-checkbox> -->
<label ng-repeat="cat in categorias[0].cats" style="display:block;" layout="row" flex="100">
<input type="checkbox" checklist-model="item.cats" checklist-value="cat.id"> {{cat.name}}
</label>
</div>
</md-card-content>
</md-card>
<md-card>
<md-card-content ng-controller="MediaController">
<h2>Imagem em Destaque</h2>
<div class="input-group form-group">
<figure ng-if="item.image"><img ng-model="item.image" ng-src="item.image" alt=""></figure>
<md-button class="md-raised" type="button" ng-click="chooseMedia($event)">Escolha uma Imagem</md-button>
</div>
</md-card-content>
</md-card>
</div>
</div>
</form>
Controller:
module.controller('MediaController', ['$scope', '$mdDialog', 'Media', function($scope, $mdDialog, Media) {
$scope.chooseMedia = function(ev){
$mdDialog.show({
parent : angular.element(document.body),
controller : chooseMediaControl,
ariaLabel : 'Choose Media',
targetEvent : ev,
clickOutsideToClose : true,
templateUrl : 'partials/tpl/media.html'
})
function chooseMediaControl($scope, $mdDialog, Media) {
$scope.media = Media.query();
$scope.cancelMedia = function() {
$mdDialog.cancel();
};
$scope.applyMedia = function() {
$scope.item.image = $scope.image;
$mDialog.hide();
};
$scope.inserMedia = function(imageurl){
$scope.image = imageurl;
};
}
}
}])
Service:
.factory('Media',function($resource){
return $resource('http://localhost:5000/media/:id',{id:'#id'},{
update: {
method: 'PUT'
}
});
})

Angular Material 0.9.7 Form Validation Example

I want to validate form using angularjs and angular-material built-in directives including messages under field like, input, select, radio buttons.
There are some specific requirements:
The Form fields should have equal heights
The radio buttons i.e. md-radio should be inline
The location of messages under fields should be similar
The angular-material select i.e. md-select should be width = 100%
I did some tweaks to Salal Aslam answer:
submit button is enable
erorr messages aren't shown on untouched form
validate on submit
validate on touching element
Example on JSFiddle and below.
HTML:
<form name="myForm" ng-app="myApp" ng-controller="myController" class="container-fluid" ng-submit="myForm.$valid && submit()" novalidate>
<div class="row">
<div class="col-xs-8">
<md-input-container md-is-error="myForm.name.$invalid && (myForm.$submitted || myForm.name.$dirty)">
<label>Name</label>
<input name="name" id="name" ng-model="obj.name" ng-required="true">
<div ng-messages="myForm.name.$error" ng-if="myForm.$submitted || myForm.name.$touched">
<div ng-message="required">Campaign Name is required.</div>
</div>
</md-input-container>
</div>
<div class="col-xs-8">
<md-input-container md-is-error="myForm.myselect.$invalid && (myForm.$submitted || myForm.myselect.$dirty)">
<md-select name="myselect" id="myselect" placeholder="myselect" ng-model="obj.myselect" ng-required="true">
<md-option ng-repeat="o in options" ng-value="o">{{o}}</md-option>
</md-select>
<div ng-messages="myForm.myselect.$error" ng-if="myForm.$submitted || myForm.myselect.$touched">
<div ng-message="required">myselect is required.</div>
</div>
</md-input-container>
</div>
<div class="col-xs-8">
<md-input-container md-is-error="myForm.status.$invalid && (myForm.$submitted || myForm.status.$dirty)">
<md-radio-group name="status" id="status" ng-model="obj.status" ng-required="true" class="">
<md-radio-button ng-repeat="s in statuses" ng-value="s">{{s}}</md-radio-button>
</md-radio-group>
<div ng-messages="myForm.status.$error" ng-if="myForm.$submitted || myForm.status.$touched">
<div ng-message="required">status is required.</div>
</div>
</md-input-container>
</div>
</div>
<md-button type="button" ng-click="reset()">RESET</md-button>
<md-button type="submit" class="md-primary">SUBMIT</md-button>
</form>
JS:
var app = angular
.module('myApp', ['ngAnimate', 'ngAria', 'ngMaterial', 'ngMessages'])
.controller('myController', function ($scope) {
$scope.statuses = ['Planned', 'Confirmed', 'Cancelled'];
$scope.options = ['Option 1', 'Option 2', 'Option 3', 'Option 4', '...'];
$scope.submit = function() {
// submit code goes here
};
$scope.reset = function() {
$scope.obj = {
name: "",
myselect: "",
status: ""
}
};
$scope.reset();
});
I created this fiddle for the requirements mentioned. I am posting this here to help someone new to angularjs or angular-material
<form name="myForm" ng-app="myApp" ng-controller="myController" class="container-fluid" ng-submit="submit()">
<div class="row">
<div class="col-xs-8">
<md-input-container>
<label>Name</label>
<input name="name" id="name" ng-model="obj.name" ng-required="true">
<div ng-messages="myForm.name.$error">
<div ng-message="required">Campaign Name is required.</div>
</div>
</md-input-container>
</div>
<div class="col-xs-8">
<md-input-container>
<md-select name="myselect" id="myselect" placeholder="myselect" ng-model="obj.myselect" ng-required="true">
<md-option ng-repeat="o in options" ng-value="o">{{o}}</md-option>
</md-select>
<div ng-messages="myForm.myselect.$error">
<div ng-message="required">myselect is required.</div>
</div>
</md-input-container>
</div>
<div class="col-xs-8">
<md-input-container>
<md-radio-group name="status" id="status" ng-model="obj.status" ng-required="true" class="">
<md-radio-button ng-repeat="s in statuses" ng-value="s">{{s}}</md-radio-button>
</md-radio-group>
<div ng-messages="myForm.status.$error">
<div ng-message="required">myselect is required.</div>
</div>
</md-input-container>
</div>
</div>
<md-button type="button" ng-click="reset()">RESET</md-button>
<md-button class="md-primary" ng-disabled="myForm.$invalid">SUBMIT</md-button>
</form>
var app = angular
.module('myApp', ['ngAnimate', 'ngAria', 'ngMaterial', 'ngMessages'])
.controller('myController', function ($scope) {
$scope.statuses = ['Planned', 'Confirmed', 'Cancelled'];
$scope.options = ['Option 1', 'Option 2', 'Option 3', 'Option 4', '...'];
$scope.submit = function() {
// submit code goes here
};
$scope.reset = function() {
$scope.obj = {
name: "",
myselect: "",
status: ""
}
}
$scope.reset();
});
md-input-container > md-select {
margin-top: 0;
padding-bottom: 0; }
md-input-container > md-select > md-select-label {
width: 100%; }
md-input-container > md-radio-group {
padding: 24px 2px 0; }
md-input-container > md-radio-group > md-radio-button {
margin: 8px 5px 0;
display: inline-block; }
fiddle link
Update 1: Created this pen for angular 1.4.2 and angular-material v0.10.0

Resources