Number format for Angular JS - html

I'm doing number formatting in Angular JS for account numbers for a banking application.
How can I implement account format 11-02980-1. I want the delimiter (-) to be added automatically to the input text when some adds the numbers (11029801). i.e when i type 11, the delimiter (-) is added and then 02980, another delimiter is added and then lastly 1
Thanks

EDIT
Is this what you were looking for?
Try this snippet:
var MyApp = angular.module('MyApp', []);
MyApp.controller('TestController', TestController);
function TestController($scope) {
$scope.accNumber = '';
$scope.previousAccNumber = '';
$scope.editAccountNumber = function (accNumber) {
if ($scope.previousAccNumber.length > accNumber.length) {
$scope.previousAccNumber = accNumber;
return accNumber;
}
accNumber = accNumber.replace(/-/g, '');
var classA = accNumber.slice(0, 2);
var classB = accNumber.slice(2, 7);
var classC = accNumber.slice(7, 8);
var finalNumber = [];
if (classA && classA.length == 2) {
finalNumber.push(classA, "-");
} else {
return classA;
}
if (classB && classB.length == 5) {
finalNumber.push(classB, "-");
} else {
return classA + "-" + classB;
}
if (classC && classC.length == 1) {
finalNumber.push(classC);
}
$scope.previousAccNumber = finalNumber.join('');
return finalNumber.join('');
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app>
<div ng-controller="TestController">
<input id="accNumber" type="text" placeholder="Enter Account Number" ng-model="accNumber" ng-change="accNumber = editAccountNumber(accNumber)" />
</div>
</div>

Related

Grouping the tables with dropdown box

I am a beginner in google app script. So right now I am doing a project where users can sign in and can view their payment history. So for now it is just showing from 2020 until 2021. So I want your guys help on creating a dropdown box which states (eg : 2020 , 2021 ) so maybe if the user clicks 2020 then they can see the payment history of 2020 only. I really need your guys help in this thing. I have attached the link to my google app script and a image to explain myself better. Thank you guys.
https://script.google.com/d/1DdRKqUX__-ZITUgTZanQ_A7hUL1kcc0TZOeFmn58wYsX_o_7cqNExnYo/edit?usp=sharing - Link to my appscript
First image
Second Image
Here is a sample code you can refer with:
WebAppLogin.html (modifications)
<script>
function GetRecords() {
var spin = "<span class=\"spinner-border spinner-border-sm\" role=\"status\" aria-hidden=\"true\"></span>";
spin += " Loading...";
document.getElementById("LoginButton").innerHTML = spin;
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
google.script.run.withSuccessHandler(function(output) {
console.log(output);
var username = output[1];
var name = output[2];
if(output[0] == 'TRUE') {
document.getElementById("errorMessage").innerHTML = "";
document.getElementById("currentUser").value = username;
google.script.run.withSuccessHandler(displayTable).GetRecords(username,"None");
} else if(output[0] == 'FALSE') {
document.getElementById("firstLastName").innerHTML = "";
document.getElementById("currentUser").value = "";
document.getElementById("myFilter").innerHTML = "";
document.getElementById("errorMessage").innerHTML = "Failed to Login";
document.getElementById("LoginButton").innerHTML = "Login";
}
}).checkLogin(username, password);
}
function filter(){
var filterStr = document.getElementById("filterYear").value;
var user = document.getElementById("currentUser").value;
google.script.run.withSuccessHandler(displayTable).GetRecords(user,filterStr);
}
function displayTable(result) {
var ar = result.data;
var filterString = result.filter;
var username = document.getElementById("currentUser").value;
if(ar.length > 0) {
var displayTable = '<table class=\"table\" id=\"mainTable\" >';
displayTable += "<tr>";
displayTable += "<th>Month</th>";
displayTable += "<th>House Number</th>";
displayTable += "<th>Street</th>";
displayTable += "<th>Payment Status</th>";
displayTable += "</tr>";
ar.forEach(function(item, index) {
displayTable += "<tr>";
displayTable += "<td>"+item[0]+"</td>";
displayTable += "<td>"+item[1]+"</td>";
displayTable += "<td>"+item[2]+"</td>";
displayTable += "<td>"+item[3]+"</td>";
displayTable += "</tr>";
});
displayTable += "</table>";
} else {
var displayTable = "<span style=\"font-weight: bold\" >No Records Found</span>";
}
var filter = '';
if(filterString.length > 0) {
filter += '<label for="years" style="font-size: 20px">Years</label><br><select class="form-control form-control-sm" id="filterYear" name="years" required><option value="" selected>Choose...</option>';
filterString.forEach(str => {
filter += '<option value="'+str+'">'+str+'</option>';
});
filter += '</select><button class="btn btn-primary" type="button" id="FilterButton" onclick="filter()" >Submit</button>';
}
//var filter = '<label for="years" style="font-size: 20px">Years</label><br><select class="form-control form-control-sm" id="filterYear" name="years" required><option value="" selected>Choose...</option><option value="2020">2020</option><option value="2021">2021</option></select><button class="btn btn-primary" type="button" id="FilterButton" onclick="filter()" >Submit</button>';
document.getElementById("digitalgoods-030521182921-1").style.display = "block";
document.getElementById("displayRecords").innerHTML = displayTable;
document.getElementById("firstLastName").innerHTML = "USER: " + name;
document.getElementById("myFilter").innerHTML = filter;
document.getElementById("LoginButton").innerHTML = "Login";
document.getElementById("username").value = '';
document.getElementById("password").value = '';
}
</script>
<div>
<h2 id="firstLastName">
</h2>
</div>
<input type="hidden" id="currentUser" value=""/>
<div id ="myFilter" class="form-group">
</div>
</div>
<div id="displayRecords" style="padding: 10px;" >
</div>
Modifications done:
Include empty form-group class
Include hidden input to hold current logged-in user
Create a reusable function displayTable()
Create an html content for the drop-down filter. See variable filter.
Include another argument when calling GetRecords(username, filter)
Create a new function filter()
During initial log-in, filter will be set to "None". filter will be set depending on the option selected
Code.gs (modifications)
function GetRecords(username,filter) {
var filteredDataRangeValues = GetUsernameAssociatedProperties(username);
var resultArray = GetPaymentRecords(filteredDataRangeValues,filter);
var resultFilter = getYears();
result = {
data: resultArray,
filter: resultFilter
};
return result;
}
function getYears() {
var ss= SpreadsheetApp.openByUrl(url);
var yearSheet = ss.getSheetByName("Configuration");
var getLastRow = yearSheet.getLastRow();
var return_array = [];
for(var i = 2; i <= getLastRow; i++)
{
if(return_array.indexOf(yearSheet.getRange(i, 2).getDisplayValue()) === -1) {
return_array.push(yearSheet.getRange(i, 2).getDisplayValue());
}
}
return return_array;
}
function GetPaymentRecords(userProperties,filter) {
var transpose = m => m[0].map((_, i) => m.map(x => x[i]));
var resultArray = [];
var ss = SpreadsheetApp.openByUrl(url);
var displaySheet = ss.getSheetByName(streetSheetName);
var addressValues = displaySheet.getRange("B:C").getValues();
var paidMonthValues = displaySheet.getRange("G:AD").getValues();
//Logger.log(addressValues);
//Logger.log(transpose(paidMonthValues));
userProperties.forEach((v, i) => {
var userHouseNumber = v[1];
var userStreet = v[2];
var column = addressValues.reduce(function callbackFn(accumulator, currentValue, index, array) {
if (currentValue[0] == userHouseNumber && currentValue[1] == userStreet) {
return index
} else {
return accumulator
}
}, '');
//Logger.log(column);
Logger.log(filter)
Logger.log(paidMonthValues);
if(filter=="None"){
var result = transpose(paidMonthValues).map(function callbackFn(element, index, array) {
return [element[0], userHouseNumber, userStreet, element[column] || '']
});
}else{
var result = transpose(paidMonthValues).map(function callbackFn(element, index, array) {
if(element[0].includes(filter))return [element[0], userHouseNumber, userStreet, element[column] || '']
});
}
resultArray = resultArray.concat(result);
//Logger.log(resultArray);
})
//Remove null elements
resultArray = resultArray.filter(element=>{
Logger.log(element!=null)
return element != null;
});
return resultArray;
}
Modifications done:
Modified GetRecords() and GetPaymentRecords() to include filter option
Add removal of null elements in the resultArray. (Null elements may exist when filter option was used due to the map() used)
Output:
(After user logged-in)
(After user selects a filter)
(UPDATE):
The following modifications where done to create a drop-box based on the list of years available in the configuration sheet.
WebAppLogin.html
displayTable() was modified that will accept an object as its parameter which contains an array data and an array of filter strings.
displayTable() was modified to update the drop-down options based on the filter strings available
Code.gs
getYears() was added that will read the sheet "Configuration" to get the filter string values
GetRecords() was modified to return an object which contains an array of record data and an array of filter strings.

Best way to change html header on User Login AngularJS

I'm working on an Angular Application in which the main page (where the angular module is initialize) has a header where I want to show different divs if the user is logged or not.
Here is the header code fragment of the index.html:
<header ng-controller="HeaderController">
<div class="container">
<div class="row">
<div class="col-lg-12 col-xs-12">
<div class="col-lg-3 col-md-3 col-sm-6 col-xs-6 none">
<a class="navbar-brand" href="#page-top"><img src="Content/img/logo.png" class="img-responsive" alt="logo"></a>
</div>
<div class="col-lg-3 col-md-3 col-sm-3 col-xs-4 col-lg-offset-6 col-md-offset-6 col-sm-offset-9" ng-if="showloginheader">
<!--ng-if="showloginheader"-->
<span href="#" class="button-login" id="toggle-login" ng-click="OnLoginClick()">Ingresar</span><img src="Content/img/logo.png" id="logo_min" alt="logo">
<div id="login" ng-controller="LoginController">
<form name="loginForm" ng-submit="login()" role="form">
<input type="text" placeholder="Ingresá el usuario" required ng-model="username" />
<input type="password" placeholder="Ingresá la contraseña" required ng-model="password" />
<!--<input type="submit" class="login" value="Ingresar" />-->
<input type="checkbox" id="checkbox" checked><div class="reco-contra">Recordar contraseña</div>
<div class="olvi-contra"><a>Olvidaste la contraseña?</a></div>
<!--<div class="form-actions">-->
<input type="submit" class="login" value="Ingresar" /> <!-- ng-disabled="form.$invalid || vm.dataLoading" -->
<input type="submit" id="clase-fb" value="Ingresar con Facebook" />
<input type="submit" id="clase-tw" value="Ingresar con Twitter" />
<input type="submit" id="clase-goo" value="Ingresar con Google" />
<div class="olvi-contra"><a>Olvidaste la contraseña?</a></div>
</form>
<input type="submit" value="¡Registrate ahora!" />
</div>
</div>
<div class="col-lg-3 col-md-3 col-sm-3 col-xs-4 col-lg-offset-6 col-md-offset-6 col-sm-offset-9" ng-if="showcurrentuserheader"><!--ng-if="showcurrentuserheader"-->
<span href="#" class="log-img" id="toggle-login"><img src="img/fefe.png" alt="logo">Pablo</span>
<div id="login">
<div id="login-ok">
<div class="opcion-log">
<strong>RECETAS OBTENIDAS</strong>
</div>
<div class="opcion-log">
<i class="fa fa-cog fa-spin"></i> PERFIL
</div>
<div class="opcion-log">
CERRAR SESION
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</header>
You can notice that there are two divs below the logo, what I want to achieve is to show the first div (the one that has a "ng-if=showloginheader") meanwhile the user isn't logged in and then show the other one when the user gets into the application (has a "ng-if=showcurrentuserheader").
I would like to know which would be the best option to do this, until now I have tried to do it with the ng-if directive.
First I initialize the variables throw a service (to make it accesible by several controllers):
(function () {
'use strict';
angular
.module('iziCooker')
.factory('UserService', UserService);
UserService.$inject = ['$http'];
function UserService($http) {
var service = {};
var showloginheader = true;
var showcurrentuserheader = false;
service.GetLoginHeaderState = GetLoginHeaderState;
service.GetCurrentUserHeaderState = GetCurrentUserHeaderState;
service.ChangeHeadersVisibility = ChangeHeadersVisibility;
return service;
function GetLoginHeaderState() {
return showloginheader;
}
function GetCurrentUserHeaderState() {
return showcurrentuserheader;
}
function ChangeHeadersVisibility() {
showloginheader = false;
showcurrentuserheader = true;
}
}
})();
Then I assign those values in the HeaderController:
(function () {
'use strict';
angular
.module('iziCooker')
.controller('HeaderController', HeaderController);
HeaderController.$inject = ['$scope', 'UserService'];
function HeaderController($scope, UserService) {
$scope.showloginheader = UserService.GetLoginHeaderState();
$scope.showcurrentuserheader = UserService.GetCurrentUserHeaderState();
}
})();
Up to this point, this works properly because the HeaderController is injected when the application starts (it's in the "master page" of Angular, index.html).
But then I tried to change the variables values in the login controller after you got a successful response from the DB to get into the application.
(function () {
'use strict';
angular
.module('iziCooker')
.controller('LoginController', LoginController);
LoginController.$inject = ['$location', 'AuthenticationService', 'FlashService', '$scope', 'UserService'];
function LoginController($location, AuthenticationService, FlashService, $scope, UserService) {
$scope.dataLoading = false;
$scope.username = "";
$scope.password = "";
console.log("Login Controller Loaded!");
//vm.login = login;
(function initController() {
// reset login status
AuthenticationService.ClearCredentials();
})();
$scope.login = function login() {
$scope.dataLoading = true;
AuthenticationService.Login($scope.username, $scope.password, function (response) {
if (response.success) {
AuthenticationService.SetCredentials($scope.username, $scope.username);
UserService.ChangeHeadersVisibility();
$location.path('/map');
} else {
FlashService.Error(response.message);
$scope.dataLoading = false;
}
});
};
}
})();
When I am redirected to the "/map" view, it still shows the first div. It seems that those ng-if variables aren't updated or something like that. Perhaps I'm missing something.
I'm almost sure that this isn't the way to do this, so I would to know if I must change something or change completely the code.
Thank you.
Edit:
Authentication Service
(function () {
'use strict';
angular
.module('iziCooker')
.factory('AuthenticationService', AuthenticationService);
AuthenticationService.$inject = ['$http', '$cookieStore', '$rootScope', '$timeout', 'UserService'];
function AuthenticationService($http, $cookieStore, $rootScope, $timeout, UserService) {
var service = {};
service.Login = Login;
service.SetCredentials = SetCredentials;
service.ClearCredentials = ClearCredentials;
return service;
function Login(username, password, callback) {
/* Dummy authentication for testing, uses $timeout to simulate api call
----------------------------------------------*/
//$timeout(function () {
// var response;
// UserService.GetByUsername(username)
// .then(function (user) {
// if (user !== null && user.password === password) {
// response = { success: true };
// } else {
// response = { success: false, message: 'Username or password is incorrect' };
// }
// callback(response);
// });
//}, 1000);
/* Use this for real authentication
----------------------------------------------*/
$http.post('ws/api/Usuario/Login', { username: username, password: password })
.success(function (response) {
callback(response);
});
}
function SetCredentials(username, password) {
var authdata = Base64.encode(username + ':' + password);
$rootScope.globals = {
currentUser: {
username: username,
authdata: authdata
}
};
$http.defaults.headers.common['Authorization'] = 'Basic ' + authdata; // jshint ignore:line
$cookieStore.put('globals', $rootScope.globals);
}
function ClearCredentials() {
$rootScope.globals = {};
$cookieStore.remove('globals');
$http.defaults.headers.common.Authorization = 'Basic';
}
}
// Base64 encoding service used by AuthenticationService
var Base64 = {
keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
encode: function (input) {
var output = "";
var chr1, chr2, chr3 = "";
var enc1, enc2, enc3, enc4 = "";
var i = 0;
do {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
this.keyStr.charAt(enc1) +
this.keyStr.charAt(enc2) +
this.keyStr.charAt(enc3) +
this.keyStr.charAt(enc4);
chr1 = chr2 = chr3 = "";
enc1 = enc2 = enc3 = enc4 = "";
} while (i < input.length);
return output;
},
decode: function (input) {
var output = "";
var chr1, chr2, chr3 = "";
var enc1, enc2, enc3, enc4 = "";
var i = 0;
// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
var base64test = /[^A-Za-z0-9\+\/\=]/g;
if (base64test.exec(input)) {
window.alert("There were invalid base64 characters in the input text.\n" +
"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
"Expect errors in decoding.");
}
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
do {
enc1 = this.keyStr.indexOf(input.charAt(i++));
enc2 = this.keyStr.indexOf(input.charAt(i++));
enc3 = this.keyStr.indexOf(input.charAt(i++));
enc4 = this.keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
chr1 = chr2 = chr3 = "";
enc1 = enc2 = enc3 = enc4 = "";
} while (i < input.length);
return output;
}
};
})();
The best way to implement something like this would be to set/unset a user object in your AuthenticationService. Then you can set a scope variable like $scope.authentication and make ng-if (or ng-show) dependent on the user object.
Since it looks like you are setting up a user model in $rootScope you can use it anywhere.
$rootScope.globals = {
currentUser: {
username: username,
authdata: authdata
}
};
So in your markup you will have this for the not logged in header:
<div ... ng-hide="$root.globals.currentUser">
And for the logged in header:
<div ... ng-show="$root.globals.currentUser">
You can also try ng-show and ng-hide:
HTML
<h1 ng-show="toggleHeader">First header</h1>
<h1 ng-hide="toggleHeader">Second header</h1>
JavaScript
$scope.toggleHeader = true; //false to switch header.
Although the problem is elsewhere. Try writing {{showloginheader}} in your HTML to see if it really does change between true/false.

Add search filter inside the select dropdown in AngularJS

I want to add a search filter inside a select dropdown in angularJS.
I have used ng-options to list down the options and used filter to filter out the data in the search box , but the problem is that the search box is not coming inside(or under) select dropdown. (When I click the select dropdown, it shows a search filter and below it has all the options)
Below is the code for your reference :
<div class="rowMargin">
<label class="control-label" for="entitySel">Entity:</label>
<div class="controls">
<select id="entityId" class="input-medium" type="text" name="entityId" ng-model="payment.entityId" ng-options="entityOpt for entityOpt in paymentEntityOptions">
<option value="">Select</option>
</select>
<span ng-show=" submitted && addPayment.entityId.$error.required">
<label class="error">Please provide entity Id </label>
</span>
<div ng-show="payment.entityId == \'Individual\'">
<span>
<select ng-model="payment.entity.individual" ng-options = "individual for individual in individualEntities | filter : filterEntity">
<option value="">Select Individual Entity</option>
<option>
<input type="search" placeholder="Search" ng-model="filterEntity"></input>
</option>
</select>
</span>
</div>
<div ng-show="payment.entityId == \'Group\'">
<span>
<select ng-model="payment.entity.group" ng-options = "group for group in groupEntities | filter : filterEntity">
<option value="">Select Group Entity</option>
<input type="search" placeholder="Search" ng-model="filterEntity"></input>
</select>
</span>
</div>
</div>
I have used the bootstrap button with class 'dropdown-toggle' and on click of the button I have appended an input search box as following :
<div class="dropdown pull-right makePaymentDropdownMainDiv" auto-close="outsideClick">
<button class="btn btn-default dropdown-toggle makePaymentDropdownBtn" type="button" id="individualDrop" data-toggle="dropdown">{{payment.entity}}<span class="caret pull-right"></span></button>
<span ng-show="submitted"><label class="error">Select an Individual</label></span>
<ul class="dropdown-menu makePaymentDropdownUlStyle" role="menu" aria-labelledby="individualDrop">
<input disable-auto-close type="search" ng-model="serchFilter" class="makePaymentDropdownSearchBox" placeholder="Search"></input>
<li role="presentation" ng-repeat="indi in individuals | filter: serchFilter"><a role="menuitem" ng-click="selectEntity(indi)">{{indi}}</a></li>
</ul>
</div>
Showing the 'li' using ng-repeat.
Remember to add auto-close="outsideClick" to your dropdown so that it doesn't close on filtering attempt.
Sorry, I'm rather late to the party, but to me it sounds like you need acute-select, an open source extension (MIT license) to Angular that does exactly this, without further dependencies.
They also have a demo page, which shows what it can do nicely.
you can use easy and best way to search filter inside the select dropdown in AngularJS
Working Demo : http://plnkr.co/edit/o767Mg6fQoyc7jKq77If?p=preview
(function (angular, undefined) {
'use strict';
// TODO: Move to polyfill?
if (!String.prototype.trim) {
String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g, '');
};
}
/**
* A replacement utility for internationalization very similar to sprintf.
*
* #param replace {mixed} The tokens to replace depends on type
* string: all instances of $0 will be replaced
* array: each instance of $0, $1, $2 etc. will be placed with each array item in corresponding order
* object: all attributes will be iterated through, with :key being replaced with its corresponding value
* #return string
*
* #example: 'Hello :name, how are you :day'.format({ name:'John', day:'Today' })
* #example: 'Records $0 to $1 out of $2 total'.format(['10', '20', '3000'])
* #example: '$0 agrees to all mentions $0 makes in the event that $0 hits a tree while $0 is driving drunk'.format('Bob')
*/
function format(value, replace) {
if (!value) {
return value;
}
var target = value.toString();
if (replace === undefined) {
return target;
}
if (!angular.isArray(replace) && !angular.isObject(replace)) {
return target.split('$0').join(replace);
}
var token = angular.isArray(replace) && '$' || ':';
angular.forEach(replace, function (value, key) {
target = target.split(token + key).join(value);
});
return target;
}
var module = angular.module('AxelSoft', []);
module.value('customSelectDefaults', {
displayText: 'Select...',
emptyListText: 'There are no items to display',
emptySearchResultText: 'No results match "$0"',
addText: 'Add',
searchDelay: 300
});
module.directive('customSelect', ['$parse', '$compile', '$timeout', '$q', 'customSelectDefaults', function ($parse, $compile, $timeout, $q, baseOptions) {
var CS_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/;
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elem, attrs, controller) {
var customSelect = attrs.customSelect;
if (!customSelect) {
throw new Error('Expected custom-select attribute value.');
}
var match = customSelect.match(CS_OPTIONS_REGEXP);
if (!match) {
throw new Error("Expected expression in form of " +
"'_select_ (as _label_)? for _value_ in _collection_[ track by _id_]'" +
" but got '" + customSelect + "'.");
}
elem.addClass('dropdown custom-select');
// Ng-Options break down
var displayFn = $parse(match[2] || match[1]),
valueName = match[3],
valueFn = $parse(match[2] ? match[1] : valueName),
values = match[4],
valuesFn = $parse(values),
track = match[5],
trackByExpr = track ? " track by " + track : "",
dependsOn = attrs.csDependsOn;
var options = getOptions(),
timeoutHandle,
lastSearch = '',
focusedIndex = -1,
matchMap = {};
var itemTemplate = elem.html().trim() || '{{' + (match[2] || match[1]) + '}}',
dropdownTemplate =
'<a class="dropdown-toggle" data-toggle="dropdown" href ng-class="{ disabled: disabled }">' +
'<span>{{displayText}}</span>' +
'<b></b>' +
'</a>' +
'<div class="dropdown-menu">' +
'<div stop-propagation="click" class="custom-select-search">' +
'<input class="' + attrs.selectClass + '" type="text" autocomplete="off" ng-model="searchTerm" />' +
'</div>' +
'<ul role="menu">' +
'<li role="presentation" ng-repeat="' + valueName + ' in matches' + trackByExpr + '">' +
'<a role="menuitem" tabindex="-1" href ng-click="select(' + valueName + ')">' +
itemTemplate +
'</a>' +
'</li>' +
'<li ng-hide="matches.length" class="empty-result" stop-propagation="click">' +
'<em class="muted">' +
'<span ng-hide="searchTerm">{{emptyListText}}</span>' +
'<span class="word-break" ng-show="searchTerm">{{ format(emptySearchResultText, searchTerm) }}</span>' +
'</em>' +
'</li>' +
'</ul>' +
'<div class="custom-select-action">' +
(typeof options.onAdd === "function" ?
'<button type="button" class="btn btn-primary btn-block add-button" ng-click="add()">{{addText}}</button>' : '') +
'</div>' +
'</div>';
// Clear element contents
elem.empty();
// Create dropdown element
var dropdownElement = angular.element(dropdownTemplate),
anchorElement = dropdownElement.eq(0).dropdown(),
inputElement = dropdownElement.eq(1).find(':text'),
ulElement = dropdownElement.eq(1).find('ul');
// Create child scope for input and dropdown
var childScope = scope.$new(true);
configChildScope();
// Click event handler to set initial values and focus when the dropdown is shown
anchorElement.on('click', function (event) {
if (childScope.disabled) {
return;
}
childScope.$apply(function () {
lastSearch = '';
childScope.searchTerm = '';
});
focusedIndex = -1;
inputElement.focus();
// If filter is not async, perform search in case model changed
if (!options.async) {
getMatches('');
}
});
if (dependsOn) {
scope.$watch(dependsOn, function (newVal, oldVal) {
if (newVal !== oldVal) {
childScope.matches = [];
childScope.select(undefined);
}
});
}
// Event handler for key press (when the user types a character while focus is on the anchor element)
anchorElement.on('keypress', function (event) {
if (!(event.altKey || event.ctrlKey)) {
anchorElement.click();
}
});
// Event handler for Esc, Enter, Tab and Down keys on input search
inputElement.on('keydown', function (event) {
if (!/(13|27|40|^9$)/.test(event.keyCode)) return;
event.preventDefault();
event.stopPropagation();
switch (event.keyCode) {
case 27: // Esc
anchorElement.dropdown('toggle');
break;
case 13: // Enter
selectFromInput();
break;
case 40: // Down
focusFirst();
break;
case 9:// Tab
anchorElement.dropdown('toggle');
break;
}
});
// Event handler for Up and Down keys on dropdown menu
ulElement.on('keydown', function (event) {
if (!/(38|40)/.test(event.keyCode)) return;
event.preventDefault();
event.stopPropagation();
var items = ulElement.find('li > a');
if (!items.length) return;
if (event.keyCode == 38) focusedIndex--; // up
if (event.keyCode == 40 && focusedIndex < items.length - 1) focusedIndex++; // down
//if (!~focusedIndex) focusedIndex = 0;
if (focusedIndex >= 0) {
items.eq(focusedIndex)
.focus();
} else {
focusedIndex = -1;
inputElement.focus();
}
});
resetMatches();
// Compile template against child scope
$compile(dropdownElement)(childScope);
elem.append(dropdownElement);
// When model changes outside of the control, update the display text
controller.$render = function () {
setDisplayText();
};
// Watch for changes in the default display text
childScope.$watch(getDisplayText, setDisplayText);
childScope.$watch(function () { return elem.attr('disabled'); }, function (value) {
childScope.disabled = value;
});
childScope.$watch('searchTerm', function (newValue) {
if (timeoutHandle) {
$timeout.cancel(timeoutHandle);
}
var term = (newValue || '').trim();
timeoutHandle = $timeout(function () {
getMatches(term);
},
// If empty string, do not delay
(term && options.searchDelay) || 0);
});
// Support for autofocus
if ('autofocus' in attrs) {
anchorElement.focus();
}
var needsDisplayText;
function setDisplayText() {
var locals = { };
locals[valueName] = controller.$modelValue;
var text = displayFn(scope, locals);
if (text === undefined) {
var map = matchMap[hashKey(controller.$modelValue)];
if (map) {
text = map.label;
}
}
needsDisplayText = !text;
childScope.displayText = text || options.displayText;
}
function getOptions() {
return angular.extend({}, baseOptions, scope.$eval(attrs.customSelectOptions));
}
function getDisplayText() {
options = getOptions();
return options.displayText;
}
function focusFirst() {
var opts = ulElement.find('li > a');
if (opts.length > 0) {
focusedIndex = 0;
opts.eq(0).focus();
}
}
// Selects the first element on the list when the user presses Enter inside the search input
function selectFromInput() {
var opts = ulElement.find('li > a');
if (opts.length > 0) {
var ngRepeatItem = opts.eq(0).scope();
var item = ngRepeatItem[valueName];
childScope.$apply(function () {
childScope.select(item);
});
anchorElement.dropdown('toggle');
}
}
function getMatches(searchTerm) {
var locals = { $searchTerm: searchTerm }
$q.when(valuesFn(scope, locals)).then(function (matches) {
if (!matches) return;
if (searchTerm === inputElement.val().trim()/* && hasFocus*/) {
matchMap = {};
childScope.matches.length = 0;
for (var i = 0; i < matches.length; i++) {
locals[valueName] = matches[i];
var value = valueFn(scope, locals),
label = displayFn(scope, locals);
matchMap[hashKey(value)] = {
value: value,
label: label/*,
model: matches[i]*/
};
childScope.matches.push(matches[i]);
}
//childScope.matches = matches;
}
if (needsDisplayText) setDisplayText();
}, function() {
resetMatches();
});
}
function resetMatches() {
childScope.matches = [];
focusedIndex = -1;
};
function configChildScope() {
childScope.addText = options.addText;
childScope.emptySearchResultText = options.emptySearchResultText;
childScope.emptyListText = options.emptyListText;
childScope.select = function (item) {
var locals = {};
locals[valueName] = item;
var value = valueFn(childScope, locals);
//setDisplayText(displayFn(scope, locals));
childScope.displayText = displayFn(childScope, locals) || options.displayText;
controller.$setViewValue(value);
anchorElement.focus();
typeof options.onSelect === "function" && options.onSelect(item);
};
childScope.add = function () {
$q.when(options.onAdd(), function (item) {
if (!item) return;
var locals = {};
locals[valueName] = item;
var value = valueFn(scope, locals),
label = displayFn(scope, locals);
matchMap[hashKey(value)] = {
value: value,
label: label/*,
model: matches[i]*/
};
childScope.matches.push(item);
childScope.select(item);
});
};
childScope.format = format;
setDisplayText();
}
var current = 0;
function hashKey(obj) {
if (obj === undefined) return 'undefined';
var objType = typeof obj,
key;
if (objType == 'object' && obj !== null) {
if (typeof (key = obj.$$hashKey) == 'function') {
// must invoke on object to keep the right this
key = obj.$$hashKey();
} else if (key === undefined) {
key = obj.$$hashKey = 'cs-' + (current++);
}
} else {
key = obj;
}
return objType + ':' + key;
}
}
};
}]);
module.directive('stopPropagation', function () {
return {
restrict: 'A',
link: function (scope, elem, attrs, ctrl) {
var events = attrs['stopPropagation'];
elem.bind(events, function (event) {
event.stopPropagation();
});
}
};
});
})(angular);
<body ng-app="Demo">
<div class="container" ng-controller="DemoController">
<label>Level 1</label>
<div custom-select="g for g in nestedItemsLevel1 | filter: $searchTerm" custom-select-options="level1Options" ng-model="level1"></div>
<label>Level 2</label>
<div custom-select="g for g in nestedItemsLevel2 | filter: $searchTerm" ng-model="level2" cs-depends-on="level1"></div>
</div>
<!-- basic scripts -->
<!--[if !IE]> -->
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
<!-- <![endif]-->
<!--[if IE]>
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<![endif]-->
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/2.3.2/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
<script src="js/customSelect.js"></script>
<script>
(function () {
var app = angular.module('Demo', ['AxelSoft']);
app.controller('DemoController', ['$scope', '$timeout', '$q', function ($scope, $timeout, $q) {
$scope.searchAsync = function (term) {
// No search term: return initial items
if (!term) {
return ['Item 1', 'Item 2', 'Item 3'];
}
var deferred = $q.defer();
$timeout(function () {
var result = [];
for (var i = 1; i <= 3; i++)
{
result.push(term + ' ' + i);
}
deferred.resolve(result);
}, 300);
return deferred.promise;
};
$scope.nestedItemsLevel1 = ['Item 1', 'Item 2', 'Item 3'];
$scope.level1 = $scope.nestedItemsLevel1[0];
$scope.level1Options = {
onSelect: function (item) {
var items = [];
for (var i = 1; i <= 5; i++) {
items.push(item + ': ' + 'Nested ' + i);
}
$scope.nestedItemsLevel2 = items;
}
};
$scope.nestedItemsLevel2 = [];
$scope.level1Options.onSelect($scope.nestedItemsLevel1[0]);
}]);
})();
</script>
</body>
https://docs.angularjs.org/api/ng/directive/select
There can be only one hard coded in a ngOption.

Client-Side Validation for entire model using MVC 3 (unobtrusive ajax)

I've got client-side validation working for individual properties, however, I would like to validate at the model level (2 or more properties) using client-side validation.
I'm using #Html.ValidationSummary(true) to display the validation error for the Model attribute that I created.
However, when the model error is generated, it doesn't display a message. It prevents the action from being made, but no error is displayed.
Anybody know why this would be the case?
My hunch is that it has something to do with client-side validation since server-side doesn't work in this case since I have to use an Ajax form.
Any advice would be appreciated!
Model Attribute
public class AuditDetailValidatorAttribute : ValidationAttribute, IClientValidatable
{
public AuditDetailValidatorAttribute()
{
ErrorMessage = "Must select an NCN level...";
}
public override bool IsValid(object value)
{
AuditRequirementDetail audit = value as AuditRequirementDetail;
if (audit == null || audit.AuditResult.Id == 0 || audit.AssessmentLevel.Id == 0)
{
return true;
}
else
{
return !(audit.AuditResult.Id == 4 && audit.AssessmentLevel.Id == 1);
}
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
return new List<ModelClientValidationRule>
{
new ModelClientValidationRule
{
ValidationType = "required",
ErrorMessage = this.ErrorMessage
}
};
}
}
Model Class
[AuditDetailValidator]
public class AuditRequirementDetail
{
// Constructor
public AuditRequirementDetail()
{
// instantiate the contained objects on AuditRequirementDetail creation
AssessmentLevel = new AssessmentLevel();
AuditResult = new AuditResult();
Requirement = new RequirementDetail();
Attachment = new Attachment();
Counter = 0;
}
/* rest of the code */
}
View
#model pdiqc.Models.AuditRequirement.AuditRequirementDetail
#{
var SuccessTarget = "success" + Model.DetailID;
var IsValidTarget = "IsValid" + Model.DetailID;
var PerformCompletedTarget = "PerformCompleted" + Model.DetailID;
var AuditResultTarget = "AuditResult_Id" + Model.DetailID;
var AssessmentLevelTarget = "AssessmentLevel_Id" + Model.DetailID;
var DesignatorTarget = "Designator_Id" + Model.DetailID;
var EvidenceTarget = "Evidence_Id" + Model.DetailID;
var AttachmentTarget = "Attachments_Id" + Model.DetailID;
var AuditResultReferral = "#" + AuditResultTarget;
var AssessmentLevelReferral = "#" + AssessmentLevelTarget;
var DesignatorReferral = "#" + DesignatorTarget;
var EvidenceReferral = "#" + EvidenceTarget;
var AttachmentReferral = "#" + AttachmentTarget;
}
#using (Ajax.BeginForm("PerformRequirement", "Audit", new AjaxOptions { HttpMethod = "POST", OnSuccess = "success" }, new {Class="PerformReqForm" }))
{
#Html.ValidationSummary(true)
if ((Model.AuditResult.Id == 1 && Model.AssessmentLevel.Id > 1) || Model.Evidence == string.Empty || Model.Evidence == null)
{
<input class="#IsValidTarget" name="IsValid" type="hidden" value=false />
}
else
{
<input class="#IsValidTarget" name="IsValid" type="hidden" value=true />
}
<p class="reqText">#Model.RequirementLabel.ConfigurableLabelDesc ##ViewBag.PerformCounter - #ModelMetadata.FromLambdaExpression(x => x.Requirement.Text, ViewData).SimpleDisplayText</p>
<div class="hide">
/* REST OF CODE */
}
I wrote a custom validator for a checkbox to make sure it was cheeked and had to do the following.
<script type="text/javascript">
$(function() {
$.validator.unobtrusive.adapters.addBool('requiredcheckbox', 'required');
}(jQuery));
</script>
Also include #Html.ValidationMessageFor(x=>x.yourProp)

firebug saying not a function

<script type = "text/javascript">
var First_Array = new Array();
function reset_Form2() {document.extraInfo.reset();}
function showList1() {document.getElementById("favSports").style.visibility="visible";}
function showList2() {document.getElementById("favSubjects").style.visibility="visible";}
function hideProceed() {document.getElementById('proceed').style.visibility='hidden';}
function proceedToSecond ()
{
document.getElementById("div1").style.visibility="hidden";
document.getElementById("div2").style.visibility="visible";
document.getElementById("favSports").style.visibility="hidden";
document.getElementById("favSubjects").style.visibility="hidden";
}
function backToFirst () {
document.getElementById("div1").style.visibility="visible";
document.getElementById("div2").style.visibility="hidden";
document.getElementById("favSports").style.visibility="visible";
document.getElementById("favSubjects").style.visibility="visible";
}
function reset_Form(){
document.personalInfo.reset();
document.getElementById("favSports").style.visibility="hidden";
document.getElementById("favSubjects").style.visibility="hidden";
}
function isValidName(firstStr) {
var firstPat = /^([a-zA-Z]+)$/;
var matchArray = firstStr.match(firstPat);
if (matchArray == null) {
alert("That's a weird name, try again");
return false;
}
return true;
}
function isValidZip(zipStr) {
var zipPat =/[0-9]{5}/;
var matchArray = zipStr.match(zipPat);
if(matchArray == null) {
alert("Zip is not in valid format");
return false;
}
return true;
}
function isValidApt(aptStr) {
var aptPat = /[\d]/;
var matchArray = aptStr.match(aptPat);
if(matchArray == null) {
if (aptStr=="") {
return true;
}
alert("Apt is not proper format");
return false;
}
return true;
}
function isValidDate(dateStr) {
//requires 4 digit year:
var datePat = /^(\d{1,2})(\/|-)(\d{1,2})\2(\d{4})$/;
var matchArray = dateStr.match(datePat);
if (matchArray == null) {
alert("Date is not in a valid format.");
return false;
}
return true;
}
function checkRadioFirst() {
var rb = document.personalInfo.salutation;
for(var i=0;i<rb.length;i++) {
if(rb[i].checked) {
return true;
}
}
alert("Please specify a salutation");
return false;
}
function checkCheckFirst() {
var rb = document.personalInfo.operatingSystems;
for(var i=0;i<rb.length;i++) {
if(rb[i].checked) {
return true;
}
}
alert("Please specify an operating system") ;
return false;
}
function checkSelectFirst() {
if ( document.personalInfo.sports.selectedIndex == -1)
{
alert ( "Please select a sport" );
return false;
}
return true;
}
function checkRadioSecond() {
var rb = document.extraInfo.referral;
for(var i=0;i<rb.length;i++) {
if(rb[i].checked) {
return true;
}
}
alert("Please select form of referral");
return false;
}
function checkCheckSecond() {
var rb = document.extraInfo.officeSupplies;
for(var i=0;i<rb.length;i++) {
if(rb[i].checked) {
return true;
}
}
alert("Please select an office supply option");
return false;
}
function checkSelectSecond() {
if ( document.extraInfo.colorPick.selectedIndex == 0 ) {
alert ( "Please select a favorite color" );
return false;
}
return true;
}
function check_Form(){
var retvalue = isValidDate(document.personalInfo.date.value);
if(retvalue) {
retvalue = isValidZip(document.personalInfo.zipCode.value);
if(retvalue) {
retvalue = isValidName(document.personalInfo.nameFirst.value);
if(retvalue) {
retvalue = checkRadioFirst();
if(retvalue) {
retvalue = checkCheckFirst();
if(retvalue) {
retvalue = checkSelectFirst();
if(retvalue) {
retvalue = isValidApt(document.personalInfo.aptNum.value);
if(retvalue){
document.getElementById('proceed').style.visibility='visible';
var rb = document.personalInfo.salutation;
for(var i=0;i<rb.length;i++) {
if(rb[i].checked) {
var salForm = rb[i].value;
}
}
var SportsOptions = "";
for(var j=0;j<document.personalInfo.sports.length;j++){
if ( document.personalInfo.sports.options[j].selected){
SportsOptions += document.personalInfo.sports.options[j].value + " ";
}
}
var SubjectsOptions= "";
for(var k=0;k<document.personalInfo.subjects.length;k++){
if ( document.personalInfo.subjects.options[k].selected){
SubjectsOptions += document.personalInfo.subjects.options[k].value + " ";
}
}
var osBox = document.personalInfo.operatingSystems;
var OSOptions = "";
for(var y=0;y<osBox.length;y++) {
if(osBox[y].checked) {
OSOptions += osBox[y].value + " ";
}
}
First_Array[0] = salForm;
First_Array[1] = document.personalInfo.nameFirst.value;
First_Array[2] = document.personalInfo.nameMiddle.value;
First_Array[3] = document.personalInfo.nameLast.value;
First_Array[4] = document.personalInfo.address.value;
First_Array[5] = document.personalInfo.aptNum.value;
First_Array[6] = document.personalInfo.city.value;
for(var l=0; l<document.personalInfo.state.length; l++) {
if (document.personalInfo.state.options[l].selected) {
First_Array[7] = document.personalInfo.state[l].value;
}
}
First_Array[8] = document.personalInfo.zipCode.value;
First_Array[9] = document.personalInfo.date.value;
First_Array[10] = document.personalInfo.phone.value;
First_Array[11] = SportsOptions;
First_Array[12] = SubjectsOptions;
First_Array[13] = OSOptions;
alert("Everything looks good.");
document.getElementById('validityButton').style.visibility='hidden';
}
}
}
}
}
}
}
}
/*function formAction2() {
var retvalue;
retvalue = checkRadioSecond();
if(!retvalue) {
return retvalue;
}
retvalue = checkCheckSecond();
if(!retvalue) {
return retvalue;
}
return checkSelectSecond() ;
} */
</script>
This is just a sample of the code, there are alot more functions, but I thought the error might be related to surrounding code. I have absolutely no idea why, as I know all the surrounding functions execute, and First_Array is populated.
However when I click the Proceed to Second button, the onclick attribute does not execute because Firebug says proceedToSecond is not a function
button code:
<input type="button" id="proceed" name="proceedToSecond" onclick="proceedToSecond();" value="Proceed to second form">
I had the same problem, and it's because you have a form with the same name as your function. JavaScript doesn't seem to be able to distinguish between the two, so you get the "not a function" error.
Maybe there is an error in your Javascript before that snippet given by you. If so, the rest will not be parsed by Firefox and then your function will not be defined.
The problem was resolved by changing proceedToSecond() to doIt() in both the call and the function name. I have no idea why
Hmm... I always used javascript:function_name() instead of function_name() because a few times the javascript didn't run. The name tag for the html snippet might have to be changed to a slightly different name because javascript might be getting it mixed up. Can you show us the entire javascript file because there may be a mistake/syntax error somewhere at the bottom/top.
It works on my computer, Firefox 3.5.5, Firebug 1.4.3, when inserting your code into an empty html document (<html><head/><body> code </body></html>)
Maybe there is another bug somewhere in your DOM, or in some of your other functions?
Could you possibly paste the entire source here, or maybe on a pastebin site?