<!DOCTYPE html>
<html>
<head>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.13.2/select.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/3.4.5/select2.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.8.5/css/selectize.default.css">
<!--<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/selectize.js/0.8.5/css/selectize.bootstrap3.css">-->
<link data-require="intl-tel-input@*" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/7.0.2/css/intlTelInput.css" />
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container content" ng-controller="MainController as app">
<lc-edit-preview class="lc-edit-preview" name="address"></lc-edit-preview>
<lc-edit-preview class="lc-edit-preview" name="phone"></lc-edit-preview>
<lc-edit-preview class="lc-edit-preview" name="email"></lc-edit-preview>
<lc-edit-preview class="lc-edit-preview" name="website"></lc-edit-preview>
<lc-edit-preview class="lc-edit-preview" name="type"></lc-edit-preview>
<lc-edit-preview class="lc-edit-preview" name="category"></lc-edit-preview>
<lc-edit-preview class="lc-edit-preview" name="location"></lc-edit-preview>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script data-require="intl-tel-input@*" src="https://cdnjs.cloudflare.com/ajax/libs/intl-tel-input/7.0.2/js/intlTelInput.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/api-check/7.5.5/api-check.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular-sanitize.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-formly/7.3.9/formly.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-select/0.13.2/select.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-formly-templates-bootstrap/6.2.0/angular-formly-templates-bootstrap.min.js"></script>
<script src="js/international-phone-number.js"></script>
<script src="app.js"></script>
</body>
</html>
(function (ng, doc) {
"use strict";
var config, appName, MainController, lcEditPreviewController, lcEditPreviewDirective;
appName = "app";
config = function configF(formlyConfigProvider) {
var formlyTypes, formlyWrappers;
formlyTypes = [
{
overwriteOk: true,
name: "input",
templateUrl: "tpls/input_formly.html",
defaultOptions: {templateOptions: {required: true, minlength: 3, maxlength: 100}}
},
{
overwriteOk: true,
name: "phone",
templateUrl: "tpls/input_phone_formly.html",
defaultOptions: {templateOptions: {required: true}}
},
{
overwriteOk: true,
name: "ui-select-single",
templateUrl: "tpls/formly_ui_select_single.min.html",
defaultOptions: {
templateOptions: {
required: true,
valueProp: "id",
labelProp: "name",
optionsAttr: "bs-options",
ngOptions: "option[to.valueProp] as option in to.options | filter: $select.search"
}
}
},
{
overwriteOk: true,
name: 'ui-select-single-search',
templateUrl: 'tpls/ui-select-single-async-search.html',
defaultOptions: {
templateOptions: {
required: true,
optionsAttr: "bs-options",
ngOptions: "option[to.valueProp] as option in to.options | filter: $select.search"
}
}
}
];
formlyWrappers = [
{
types: ["input", "phone"],
templateUrl: "tpls/input_formly_wrapper.html"
},
{
types: ["inputWithLabel", "ui-select-single", "ui-select-single-search"],
templateUrl: "tpls/formly_input_wrapper_with_label.min.html"
},
];
formlyConfigProvider.setType(formlyTypes);
formlyConfigProvider.setWrapper(formlyWrappers);
};
MainController = function MainControllerF() {
var app;
app = this;
};
lcEditPreviewDirective = function lcEditPreviewDirective(TPLS_ASSETS) {
return {
scope: {},
restrict: "E",
controllerAs: "lcEditPreview",
controller: "lcEditPreviewController",
templateUrl: TPLS_ASSETS + '/lc_edit_preview.min.html',
bindToController: {
name: "@"
}
};
};
lcEditPreviewController = function lcEditPreviewController($http, $q) {
var lcEditPreview, categories, locations, validateUrl, refreshAddresses;
lcEditPreview = this;
lcEditPreview.page = {};
categories = [
{id: 1, name: 'Clothing'},
{id: 2, name: 'Sport'},
{id: 3, name: 'Electronic'},
{id: 4, name: 'Decration'},
{id: 5, name: 'Garden'}
];
locations = [
{id: 1, name: 'International'},
{id: 2, name: 'France'},
{id: 3, name: 'Tunisia'},
{id: 4, name: 'Belgium'},
{id: 5, name: 'Italy'}
];
refreshAddresses = function refreshAddresses(address, field) {
var promise;
if (!address) {
promise = $q.when({data: {results: []}});
} else {
var params = {address: address, sensor: false};
var endpoint = '//maps.googleapis.com/maps/api/geocode/json';
promise = $http.get(endpoint, {params: params});
}
return promise.then(function(response) {
field.templateOptions.options = response.data.results;
});
};
validateUrl = function validateUrlF($viewValue, $modelValue, scope) {
return ($modelValue || $viewValue) ? /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?\/$/i.test( value ) : true;
};
lcEditPreview.fields = {
address: [
{
key: 'address',
type: 'ui-select-single-search',
className: 'col-lg-6',
templateOptions: {
optionsAttr: 'bs-options',
ngOptions: 'option[to.valueProp] as option in to.options | filter: $select.search',
label: 'Address',
valueProp: 'formatted_address',
labelProp: 'formatted_address',
placeholder: 'Your address',
options: [],
refresh: refreshAddresses,
refreshDelay: 0
}
}
],
phone: [
{
key: 'phone',
type: 'phone',
className: 'col-lg-6',
templateOptions: {
label: 'Phone',
type: 'text',
placeholder: 'Your phone'
}
}
],
email: [
{
key: 'email',
type: 'input',
className: 'col-lg-6',
templateOptions: {
label: 'Email',
type: 'email',
placeholder: 'example@example.com'
}
}
],
website: [
{
key: 'website',
type: 'input',
className: 'col-lg-6',
validators: {url: validateUrl},
templateOptions: {
label: 'Website',
type: 'text',
placeholder: 'Your website'
}
}
],
type: [
{
key: 'type',
type: 'input',
className: 'col-lg-6',
templateOptions: {
label: 'Type',
type: 'text',
placeholder: 'Your type'
}
}
],
category: [
{
key: "category",
type: "ui-select-single",
className: 'col-lg-6',
templateOptions: {
label: "Category",
options: categories,
placeholder: "Choose a cetegory"
}
}
],
location: [
{
key: "location",
type: "ui-select-single",
className: 'col-lg-6',
templateOptions: {
label: "Location",
options: locations,
placeholder: "Choose a location"
}
}
]
};
};
ng.module(appName, ['formly', 'formlyBootstrap', 'ngSanitize', 'ui.select', 'internationalPhoneNumber'], config)
.constant("TPLS_ASSETS", "tpls")
.controller("MainController", MainController)
.directive("lcEditPreview", lcEditPreviewDirective)
.controller("lcEditPreviewController", lcEditPreviewController);
ng.bootstrap(doc, [appName]);
}(angular, document));
.lc-reset-padding-v {
padding-left: 0;
padding-right: 0;
}
body {
background-color: #f6f6f6;
}
.content {
margin-top: 100px;
text-align: center;
}
.lc-edit-preview {
display: block;
margin-bottom: 30px;
}
.formly-field,
div[ng-transclude] {
display: inline-block;
}
.form-inline table {
margin-bottom: 0;
}
.form-inline table tr > td {
padding: 5px 10px 0;
}
.form-inline .control-label {
line-height: 30px;
}
.form-inline .form-control,
.form-inline .selectize-control,
.form-inline .ui-select-bootstrap {
display: inline-block;
}
.select2 > .select2-choice.ui-select-match {
/* Because of the inclusion of Bootstrap */
height: 29px;
}
.selectize-control > .selectize-dropdown {
top: 36px;
}
.ui-select-bootstrap > .ui-select-match > .btn {
max-width: 100%;
width: 230px;
}
<form
novalidate
name="UpdateForm"
autocomplete="off"
class="row form-inline"
ng-if="lcEditPreview.isEditMode"
>
<formly-form
class="col-lg-6 col-lg-offset-3"
model="lcEditPreview.page"
fields="lcEditPreview.fields[lcEditPreview.name]"
>
<div class="form-group">
<button
type="button"
ng-disabled="UpdateForm.$invalid"
class="btn btn-small btn-primary"
ng-click="lcEditPreview.update(lcEditPreview.name, lcEditPreview[lcEditPreview.name])"
>
Confirm
</button>
<button
type="reset"
class="btn btn-small btn-danger"
ng-click="lcEditPreview.isEditMode=false"
>
Cancel
</button>
</div>
</formly-form>
</form>
<div class="lc-preview" ng-if="!lcEditPreview.isEditMode">
{{lcEditPreview.page[lcEditPreview.fields[lcEditPreview.name].key]}}
<button class="btn btn-primary btn-sm" ng-click="lcEditPreview.isEditMode=true">Edit</button>
</div>
<div
class="formly-template-wrapper pull-left form-group"
ng-class="{
'has-success': form[id].$valid,
'has-error': options.validation.errorExistsAndShouldBeVisible
}"
>
<label for="{{id}}" class="col-lg-4 control-label lc-reset-padding-v">
{{to.label}} {{to.required ? '*' : ''}}
</label>
<div class="col-lg-8 text-right lc-reset-padding-v">
<label
ng-messages="fc.$error"
class="validation help-block"
ng-if="options.validation.errorExistsAndShouldBeVisible"
>
<div ng-messages-include="tpls/validation.min.html"></div>
<div
ng-message="{{::name}}"
ng-repeat="(name, message) in ::options.validation.messages track by $index"
>
{{message(fc.$viewValue, fc.$modelValue, this)}}
</div>
</label>
<formly-transclude></formly-transclude>
</div>
</div>
<input
id="{{id}}"
class="form-control"
formly-dynamic-name="id"
ng-disabled="to.disabled"
ng-required="to.required"
type="{{to.type || 'text'}}"
ng-model="model[options.key]"
placeholder="{{to.placeholder}}"
aria-describedby="{{id}}_description"
formly-custom-validation="options.validators"
>
<ui-select
theme="selectize"
disabled="{{to.disabled}}"
required="{{to.required}}"
ng-model="model[options.key]"
>
<ui-select-match placeholder="{{to.placeholder}}">
{{$select.selected[to.labelProp]}}
</ui-select-match>
<ui-select-choices data-repeat="{{to.ngOptions}}">
<div ng-bind-html="option[to.labelProp] | highlight: $select.search"></div>
</ui-select-choices>
</ui-select>
<div
class="formly-template-wrapper pull-left form-group"
ng-class="{
'has-success': form[id].$valid,
'has-error': options.validation.errorExistsAndShouldBeVisible
}"
>
<label for="{{id}}" class="col-lg-4 control-label lc-reset-padding-v">
{{to.label}} {{to.required ? '*' : ''}}
</label>
<div class="col-lg-8 lc-reset-padding-v">
<label
ng-messages="fc.$error"
class="validation help-block"
ng-if="options.validation.errorExistsAndShouldBeVisible"
>
<div ng-messages-include="assets/tpls/validation.min.html"></div>
<div
ng-message="{{::name}}"
ng-repeat="(name, message) in ::options.validation.messages track by $index"
>
{{message(fc.$viewValue, fc.$modelValue, this)}}
</div>
</label>
<formly-transclude></formly-transclude>
</div>
</div>
<div ng-message="required">{{to.label}} is required.</div>
<div ng-message="email">{{to.label}} is Invalid.</div>
<div ng-message="minlength, maxlength">
{{to.label}} must be between {{to.minlength}} and {{to.maxlength}}.
</div>
<div ng-message="fieldMatch">Passwords should match.</div>
<input
id="{{id}}"
class="form-control"
formly-dynamic-name="id"
ng-disabled="to.disabled"
ng-required="to.required"
type="{{to.type || 'text'}}"
ng-model="model[options.key]"
placeholder="{{to.placeholder}}"
aria-describedby="{{id}}_description"
formly-custom-validation="options.validators"
international-phone-number
>
<ui-select
theme="bootstrap"
reset-search-input="false"
ng-model="model[options.key]"
ng-required="{{to.required}}"
ng-disabled="{{to.disabled}}"
>
<ui-select-match placeholder="{{to.placeholder}}">{{$select.selected[to.labelProp]}}</ui-select-match>
<ui-select-choices
repeat="{{to.ngOptions}}"
refresh="to.refresh($select.search, options)"
refresh-delay="{{to.refreshDelay}}"
>
<div ng-bind-html="option[to.labelProp] | highlight: $select.search"></div>
<div><small>{{option.geometry.location.lat}}, {{option.geometry.location.lng}}</small></div>
</ui-select-choices>
</ui-select>
(function() {
"use strict";
angular.module("internationalPhoneNumber", []).constant('ipnConfig', {
allowExtensions: false,
autoFormat: true,
autoHideDialCode: true,
autoPlaceholder: true,
customPlaceholder: null,
defaultCountry: "",
geoIpLookup: null,
nationalMode: true,
numberType: "MOBILE",
onlyCountries: void 0,
preferredCountries: ['us', 'gb'],
skipUtilScriptDownload: false,
utilsScript: ""
}).directive('internationalPhoneNumber', [
'$timeout', 'ipnConfig', function($timeout, ipnConfig) {
return {
restrict: 'A',
require: '^ngModel',
scope: {
ngModel: '=',
country: '='
},
link: function(scope, element, attrs, ctrl) {
var handleWhatsSupposedToBeAnArray, options, read, watchOnce;
if (ctrl) {
if (element.val() !== '') {
$timeout(function() {
element.intlTelInput('setNumber', element.val());
return ctrl.$setViewValue(element.val());
}, 0);
}
}
read = function() {
return ctrl.$setViewValue(element.val());
};
handleWhatsSupposedToBeAnArray = function(value) {
if (value instanceof Array) {
return value;
} else {
return value.toString().replace(/[ ]/g, '').split(',');
}
};
options = angular.copy(ipnConfig);
angular.forEach(options, function(value, key) {
var option;
if (!(attrs.hasOwnProperty(key) && angular.isDefined(attrs[key]))) {
return;
}
option = attrs[key];
if (key === 'preferredCountries') {
return options.preferredCountries = handleWhatsSupposedToBeAnArray(option);
} else if (key === 'onlyCountries') {
return options.onlyCountries = handleWhatsSupposedToBeAnArray(option);
} else if (typeof value === "boolean") {
return options[key] = option === "true";
} else {
return options[key] = option;
}
});
watchOnce = scope.$watch('ngModel', function(newValue) {
return scope.$$postDigest(function() {
if (newValue !== null && newValue !== void 0 && newValue.length > 0) {
if (newValue[0] !== '+') {
newValue = '+' + newValue;
}
ctrl.$modelValue = newValue;
}
element.intlTelInput(options);
if (!(options.skipUtilScriptDownload || attrs.skipUtilScriptDownload !== void 0 || options.utilsScript)) {
element.intlTelInput('loadUtils', '/bower_components/intl-tel-input/lib/libphonenumber/build/utils.js');
}
return watchOnce();
});
});
scope.$watch('country', function(newValue) {
if (newValue !== null && newValue !== void 0 && newValue !== '') {
return element.intlTelInput("selectCountry", newValue);
}
});
ctrl.$formatters.push(function(value) {
if (!value) {
return value;
}
element.intlTelInput('setNumber', value);
return element.val();
});
ctrl.$parsers.push(function(value) {
if (!value) {
return value;
}
return value.replace(/[^\d]/g, '');
});
ctrl.$validators.internationalPhoneNumber = function(value) {
var selectedCountry;
selectedCountry = element.intlTelInput('getSelectedCountryData');
if (!value || (selectedCountry && selectedCountry.dialCode === value)) {
return true;
}
return element.intlTelInput("isValidNumber");
};
element.on('blur keyup change', function(event) {
return scope.$apply(read);
});
return element.on('$destroy', function() {
element.intlTelInput('destroy');
return element.off('blur keyup change');
});
}
};
}
]);
}).call(this);