I am having trouble populating my multi-select. I am using this version of the multi-select http://davidstutz.github.io/bootstrap-multiselect/
I have looked at this stack overflow page (How can I use Bootstrap Multiselect Dropdown in AngularJS) but I am still having problems. I am trying to populate my multi-select with data that I grab from a database which gets stored in provData.
Here is my html:
<div class="col-sm-8">
<select class="form-control" multiple ht-multi-select ng-model="patient.provid" ng-options="prov.id as prov.code for prov in provData">
<option value="{{prov.id}}">{{prov.code}}</option>
</select>
</div>
Here is my directive:
templates.directive('htMultiSelect', function() {
return {
replace: true,
require: 'ngModel',
scope: {},
link:function(scope, element, attrs) {
console.log($(element));
console.log('hit');
// Below setup the dropdown:
$(element).multiselect({
enableClickableOptGroups: true
});
// Below maybe some additional setup
scope.$watch(attrs.ngModel, function () {
$(element).multiselect('refresh');
});
}
};
});
My main issue is I can not populate my multi-select with data from provData and I can not get it to set the ng-model. Any help will be greatly appreciated.
Based on Rashim's blog, this is what I tried in Plunke.
https://rashimuddin.wordpress.com/2014/07/08/multi-select-drop-down-in-angularjs/
Check this out
http://plnkr.co/edit/y8VOlgeSMOqHjFxoZU1L?p=previewenter code here
HTML
<div dropdown-multiselect="" items="FirstItems" on-close="closeAlert(val)" on-Validation="addAlert(validationMsg)" max-Selection="3" selected-items="FirstSelectedItems"></div>
Angular directive would be
var app = angular.module('myApp', ['ui.bootstrap']);
app.controller('AppCtrl', ["$scope", function($scope) {
$scope.status = {
isopen: false
};
$scope.FirstItems = [];
$scope.alerts = [{
type: 'danger',
msg: 'Oh snap! Change a few things up and try submitting again.'
}, {
type: 'success',
msg: 'Well done! You successfully read this important alert message.'
}];
$scope.addAlert = function(validationMsg) {
if ($scope.validateFire === true) {
$scope.alerts.push({
msg: validationMsg
});
}
$scope.validateFire = true;
};
$scope.closeAlert = function(val) {
$scope.alerts = [];
}
for (var i = 0; i <= 20; i++) {
var obj = [];
obj["Id"] = i;
obj["Name"] = "Name" + i;
obj["IsSelected"] = false;
$scope.FirstItems.push(obj);
}
$scope.FirstSelectedItems = [];
var removeItem = function(items, item) {
for (var index = 0; index < items.length; index++) {
if (item.Id == items[index].Id) {
item.IsSelected = false;
items.splice(index, 1);
break;
}
}
};
$scope.removeFirstItem = function(item) {
removeItem($scope.FirstSelectedItems, item);
};
$scope.removeSecondItem = function(item) {
removeItem($scope.SecondSelectedItems, item);
};}]);
Directive goes like this
app.directive('dropdownMultiselect', function() {
return {
restrict: 'A',
scope: {
items: "=",
selectedItems: "=",
maxSelection: "=",
validateFire: "=",
onValidation: '&',
onClose: '&'
},
template: "" +
"" +
"Add " +
"" +
"" +
"" +
"" +
"All " +
"None" +
"" +
"" +
"" +
" " +
"{{item.Name}}" +
"" +
"" +
"",
controller: function($scope) {
$scope.handleClick = function($event) {
$event.stopPropagation();
};
$scope.status = {
isopen: false
};
$scope.status = {
isopen: false
};
$scope.openDropdown = function($event) {
if ($scope.items !== undefined && $scope.items.length > 0) {
if ($scope.items.length > $scope.maxSelection)
$scope.showAll = false;
else
$scope.showAll = true;
for (var index = 0; index < $scope.items.length; index++) {
$scope.items[index].IsSelected = false;
}
if ($scope.selectedItems !== undefined && $scope.selectedItems.length > 0) {
for (var selectedItemIndex = 0; selectedItemIndex < $scope.selectedItems.length; selectedItemIndex++) {
for (var itemIndex = 0; itemIndex < $scope.items.length; itemIndex++) {
if ($scope.selectedItems[selectedItemIndex].Id == $scope.items[itemIndex].Id) {
$scope.items[itemIndex].IsSelected = true;
break;
}
}
}
}
}
$event.stopPropagation();
$scope.status.isopen = true;
};
$scope.selectAll = function($event) {
$scope.selectedItems = [];
angular.forEach($scope.items, function(item) {
item.IsSelected = true;
$scope.selectedItems.push(item);
});
$event.stopPropagation();
};
$scope.deselectAll = function($event) {
angular.forEach($scope.items, function(item) {
item.IsSelected = false;
});
$scope.selectedItems = [];
$event.stopPropagation();
};
$scope.selectItem = function(item) {
if (item.IsSelected === false) {
for (var index = 0; index < $scope.selectedItems.length; index++) {
if (item.Id == $scope.selectedItems[index].Id) {
item.IsSelected = false;
$scope.selectedItems.splice(index, 1);
$scope.onClose({
val: "1"
});
break;
}
}
} else {
if ($scope.selectedItems.length > $scope.maxSelection) {
item.IsSelected = false;
$scope.validationMsg = "MAX_REACHED";
$scope.validateFire = true;
$scope.onValidation({
validationMsg: "Max_Reached"
});
return;
}
$scope.selectedItems.push(item);
}
};
$scope.clickItem = function($event) {
$event.stopPropagation();
};
$scope.closeDropDown = function() {
$scope.status.isopen = false;
$event.stopPropagation();
};
}
};
});`
Related
I have a multiple dropdown and i want to show/hide based on change event on dropdown. It's nested elements dropdown.
http://jsfiddle.net/U3pVM/60518/
angular.module('myApp', []).controller('CEventCtrl', ['$rootScope', '$scope',
function($rootScope, $scope) {
var $this = this;
$this.bUOptions = '[{"id":"bu_0","options":[{"id":"","name":"Not Selected"},{"id":6,"name":"Bhumi1"},{"id":12,"name":"*Sales*"},{"id":17,"name":"*Support*"}],"label":"Department","showif":null},{"id":"bu_12","options":[{"id":"","name":"Not Selected"},{"id":13,"name":"AU Sales"},{"id":14,"name":"USA Sales"}],"label":"Section","showif":"bu_0=12"},{"id":"bu_14","options":[{"id":"","name":"Not Selected"},{"id":16,"name":"USA East Sales"},{"id":15,"name":"USA West Sales"}],"label":"Region","showif":"bu_12=14&&bu_0=12"},{"id":"bu_17","options":[{"id":"","name":"Not Selected"},{"id":18,"name":"AU Support"},{"id":19,"name":"UK Support"}],"label":"Section","showif":"bu_0=17"}]';
$scope.bUn = {};
this.count = 0;
this.isBUChildElement = function(value, key) {
this.bU = {};
bU = $this.bUOptions;console.log(bU);
if (value !== '' & typeof bU[key] == 'undefined') {
if (!$scope.bUn[key]) {
$scope.bUn[key] = false;
}
}
else {
$scope.bUn[key] = true;
};
return $scope.bUn[key];
}
this.getBUChild = function(selectedValue, showif,selectedElement){
var splitKey = selectedElement.split('_')[0];
angular.forEach(bUn, function(value, key){
if(splitKey+'_'+selectedValue !== key){
bUn[key] = false;
}
bUn[splitKey+'_'+selectedValue] = true;
});
if (showif !=='') {
if (showif.indexOf("&&") === -1) {
var splitShowif = showif.split('=');
console.log('');
console.log(splitKey+'_'+splitShowif[1]);
bUn[splitKey+'_'+splitShowif[1]] = true;
}
else {
var splitShowif = showif.split('&&');
angular.forEach(splitShowif, function(value, key) {
var splitShowifParts = value.split('=');
console.log('');
console.log(splitKey+'_'+splitShowifParts[1]);
bUn[splitKey+'_'+splitShowifParts[1]] = true;
});
}
}
bUn[selectedElement] = true;
}
}
]);
But somehow it is calling multiple times and not hide properly.
I'm not able to add tag in my text field. Can anyone help me with an approach to add text in a text field as tagging. How to bing the tag to a json object or an variable.
</script>
<script>
var app = angular.module('myApp',[]);
app.directive('tagInputType', function() {
return {
restrict: 'E',
scope: { tags: '=' },
template:
'<div class="tags">' +
'<a ng-repeat="(idx, tag) in tags" class="tag" ng-click="remove(idx)">{{tag}}</a>' +
'</div>' +
'<input type="text" placeholder="Add a tag..." ng-model="new_value"></input> ' +
'<input type="button" value="Add" ng-click="add()"></input>',
link: function ( $scope, $element ) {
// var input = angular.element( $element.children()[1] );
$scope.add = function() {
$scope.tags.push( $scope.new_value );
$scope.new_value = "";
};
$scope.remove = function ( idx ) {
$scope.tags.splice( idx, 1 );
};
input.bind( 'keypress', function ( event ) {
if ( event.keyCode == 13 ) {
$scope.$apply( $scope.add );
}
});
}
};
});
app.controller('MainCtrl', function ( $scope ) {
$scope.tags = { "value1":"angular","value2":"html"};
});
</script>
<script>
App.directive('dhTag', function($compile) {
return {
restrict: 'AE',
scope: {
taglist: '=list',
autocomplete: '=autocomplete',
display: '='
},
link: function($scope, element, attrs) {
$scope.defaultWidth = 490;
$scope.tagText = "";
$scope.placeholder = attrs.placeholder;
$scope.display = attrs.display;
$scope.tagArray = function() {
return $scope.taglist || [];
};
$scope.addTag = function() {
//debugger
var tagArray;
if ($scope.tagText.length === 0) {
return;
}
tagArray = $scope.tagArray();
for (var i = 0; i < tagArray.length; i++) {
if (tagArray[i].name == $scope.tagText) {
alert("Tag already exists in the content box!!");
return;
}
}
tagArray.push({
name: $scope.tagText
});
$scope.taglist = tagArray;
$scope.tagText = "";
};
$scope.deleteTag = function(key) {
var tagArray;
tagArray = $scope.tagArray();
if (tagArray.length > 0 && $scope.tagText.length === 0 && key === undefined) {
tagArray.pop();
} else {
if (key !== undefined) {
tagArray.splice(key, 1);
}
}
$scope.taglist = tagArray;
};
$scope.$watch('tagText', function(newVal, oldVal) {
var temp;
if (!(newVal === oldVal && newVal === undefined) && temp) {
//temp = $("<span>" + newVal + "</span>").appendTo("body");
$scope.inputWidth = temp ? temp.width() : 0;
if ($scope.inputWidth < $scope.defaultWidth) {
$scope.inputWidth = $scope.defaultWidth;
}
return temp.remove();
}
});
$scope.processKey = function(e) {
var key;
key = e.which;
if (key === 9 || key === 13 || key === 188) {
$("div").find('.dh-tag-ctn .input-tag').css({
"background-color": " #FCF8E3"
});
e.preventDefault();
return $scope.addTag();
}
if (key === 8) {
$("div").find('.dh-tag-ctn .input-tag').css({
"background-color": "rgba(255, 0, 0, 0.15)"
});
$scope.deleteTag();
}
};
},
//templateUrl: "tagInputTemplate.html",
template: "" +
"<div class='dh-tag-ctn'>" +
" <div class='input-tag' ng-hide={{display}} data-ng-repeat=\"tag in tagArray() track by $index\" ng-class='tag' >" +
" <span>{{tag.name}}</span>" +
" <div class='delete-tag' data-ng-click='deleteTag($index)'> ×</div>" +
" </div>" +
" <input type='text' data-ng-style='{width: inputWidth}' ng-model='tagText' ng-keypress='processKey($event)' ng-keyup='processKey($event)' placeholder='{{placeholder}}' />" +
"</div>" +
"<br>" +
"<div ng-show={{display}} class='dh-tag-ctn-view'><div class='input-tag' data-ng-repeat=\"tag in tagArray() track by $index\" ng-class='tag'>{{tag.name}}" +
" <div class='delete-tag' data-ng-click='deleteTag($index)'>×<br></div>" +
"</div>"
};
});
</script>
below code is about dual selectlist. as shown in below image.
Its working as desire. Only problem is, if I click on last subject from Right hand side list box (select Subject list), it is moving all subject to left list box. Technically it should only move the clicked (selected) one subject.
Any suggestion to resolve this?
Code is as following
(function () {
'use strict';
angular
.module("eSchoolSystem")
.directive('multiSelect',['$compile', '$log', multiSelect])
function multiSelect($compile, $log) {
return {
restrict: 'E',
scope: {
name: '#',
selectedModel: '=',
availableModel: '='
},
/*template: '<select id="{{name}}-available" multiple ng-model="availableModel" ng-click="toSelected()" ng-options="a as a.subjectShortName for a in Model.available"></select>\n\n\
<select id="{{name}}-selected" ng-click="toAvailable()" multiple ng-model="selectedModel" ng-options="s as s.subjectShortName for s in Model.selected"></select>',
*/
templateUrl:'app/class/html/dualMultiSelect.html',
compile: function() {
return {
pre: function($scope, $elem, $attr) {
var RefreshSelect = function(original, toFilter) {
var filtered = [];
angular.forEach(original, function(entity) {
var match = false;
for (var i = 0; i < toFilter.length; i++) {
if (toFilter[i]["subjectId"] === entity["subjectId"]) {
match = true;
break;
}
}
if (!match) {
filtered.push(entity);
}
});
return filtered;
};
var RefreshModel = function() {
/*$scope.selectedModel = $scope.Model.selected;*/
$scope.selectedModel = angular.copy($scope.Model.selected);
/*$scope.availableModel = $scope.Model.available;*/
$scope.availableModel = angular.copy($scope.Model.available);
};
var Init = function() {
$scope.Model = {
available: $scope.availableModel,
selected: $scope.selectedModel
};
$scope.selectedModel = [];
$scope.availableModel = [];
$scope.toSelected = function() {
$scope.Model.selected = $scope.Model.selected.concat($scope.availableModel);
$scope.Model.available = RefreshSelect($scope.Model.available, $scope.availableModel);
RefreshModel();
};
$scope.toAvailable = function() {
console.log("in here -x1")
console.log("x3-> " + JSON.stringify($scope.selectedModel))
$scope.Model.available = $scope.Model.available.concat($scope.selectedModel);
$scope.Model.selected = RefreshSelect($scope.Model.selected, $scope.selectedModel);
RefreshModel();
};
};
Init();
}
};
}
};
}
}());
Try to remove RefreshModel function and updating selected values in toSelected and toAvailable:
$scope.toSelected = function() {
$scope.Model.selected = $scope.Model.selected.concat($scope.availableModel);
$scope.Model.available = RefreshSelect($scope.Model.available, $scope.availableModel);
$scope.selectedModel = $scope.availableModel;
$scope.availableModel = [];
};
$scope.toAvailable = function() {
$scope.Model.available = $scope.Model.available.concat($scope.selectedModel);
$scope.Model.selected = RefreshSelect($scope.Model.selected, $scope.selectedModel);
$scope.selectedModel = [];
$scope.availableModel = $scope.selectedModel;
};
I am building an Ionic app which has a list that is split using 'item divider'
The problem i am having is that when I use the buttons I have in the app to change the list order etc the divider text is not changing.
The divider text items are generated within an Angular directive.
I feel as though the problem is that the directive is not being re-called when the button is clicked.
Below is the code for the list and the directive.
I have also created a codepen to play about with if that makes things any easier.
Here is the CODEPEN LINK
Notice that when you use the search bar then delete the word the list does update
HTML/Ionic markup for the list
<ion-list id="list">
<ion-item
auto-list-divider
auto-list-divider-value="{{item[dividerString]}}"
auto-list-divider-function="dividerFunction"
ng-click="setDataSetClick(item.marker)"
ng-href="#/tab/films/{{item.id}}"
ng-repeat="item in outputData | filter:search.string | orderBy:dividerString:true">
<!-- If Film data show title p -->
<h3 ng-if="item.marker=='film';">{{item.title}}</h3>
<!-- If Cinema data show title p -->
<h3 ng-if="item.marker=='cinema';">{{item.cinema}}</h3>
</ion-item>
</ion-list>
Angular Controller
.controller('ListCtrl', function($scope, $timeout, $ionicScrollDelegate, Films, Cinemas, FilterList, OrderList, DataSetString, $ionicActionSheet) {
'use strict';
var cachedFilmData = Films.all(),
cachedCinemaData = Cinemas.all(),
indexedFilms = [];
$scope.dividerFunction = function(key) {
return key;
};
$scope.search = {
string: ''
};
$scope.dividerString = "year";
$scope.outputData = cachedFilmData;
$scope.filterString = FilterList.getFilter();
$scope.orderString = OrderList.getOrder();
$scope.itemsToFilter = function() {
indexedFilms = [];
return $scope.outputData;
};
$scope.filterFilms = function(films) {
var uniqueFilm = indexedFilms.indexOf(films[$scope.dividerString]) === -1;
if (uniqueFilm) {
indexedFilms.push(films[$scope.dividerString]);
}
return uniqueFilm;
};
$scope.setDataSetClick = function(data) {
DataSetString.setString(data);
};
// When the filter by button is clicked
$scope.showFilterActionSheet = function() {
$ionicActionSheet.show({
buttons: [{
text: 'Film'
}, {
text: 'Cinema'
}],
titleText: 'Select A Filter',
cancelText: 'Cancel',
buttonClicked: function(index, obj) {
FilterList.setFilter(obj.text);
$scope.filterString = FilterList.getFilter();
if ($scope.filterString === "Cinema") {
$scope.outputData = cachedCinemaData;
$scope.dividerString = "opened";
DataSetString.setString('cinema');
} else {
$scope.outputData = cachedFilmData;
$scope.dividerString = "year";
DataSetString.setString('film');
}
// Reset the order string tex
$scope.orderString = "Date";
return true;
}
});
};
// When the order by button is clicked
$scope.showOrderActionSheet = function() {
var activeDataSet = DataSetString.getString();
var optOne, optTwo, optThree;
if (activeDataSet === "cinema") {
optOne = "Opened";
optTwo = "Closed";
optThree = "Highlights";
} else {
optOne = 'Date';
optTwo = 'Themes';
optThree = 'Highlights';
}
$ionicActionSheet.show({
buttons: [{
text: optOne
}, {
text: optTwo
}, {
text: optThree
}],
titleText: 'Select An Order',
cancelText: 'Cancel',
buttonClicked: function(index, obj) {
var orderText = obj.text,
divider;
if (activeDataSet === "cinema") {
if (orderText === "Opened") {
divider = "opened";
}
if (orderText === "Closed") {
divider = "closed";
}
if (orderText === "Highlights") {
divider = "highlight";
}
sortData(cachedCinemaData, divider);
} else {
if (orderText === "Date") {
divider = "year";
}
if (orderText === "Themes") {
divider = "theme";
}
if (orderText === "Highlights") {
divider = "highlight";
}
sortData(cachedFilmData, divider);
}
$scope.orderString = obj.text;
$ionicScrollDelegate.scrollTop(true);
return true;
}
});
};
function sortData(data, divider) {
$scope.outputData = [];
var newOutputData = [];
for (var i = 0; i < data.length; i += 1) {
if (data[i][divider] != 0) {
console.log(divider);
newOutputData.push(data[i]);
}
}
$scope.outputData = newOutputData;
$scope.dividerString = divider;
}
})
Angular Directive
.directive('autoListDivider', function($timeout) {
var lastDivideKey = "";
return {
link: function(scope, element, attrs) {
var key = attrs.autoListDividerValue,
doDivide;
doDivide = function() {
var divideFunction = scope.$apply(attrs.autoListDividerFunction),
divideKey = divideFunction(key);
if (divideKey !== lastDivideKey) {
element.prepend(
'<h2 class="item item-divider custom--item-divider"><span ng-bind="divideKey">' + divideKey + '</span></h2>'
)
}
lastDivideKey = divideKey;
};
$timeout(doDivide, 0);
}
};
})
I am working on JQuery mechanism that is building tree, it has to be as fast as possible. Volume of data is quite large so master record column is used to be able to 'grab' all relevant nodes in one select from webSQL db.
Whole mechanism but one part is done, when assembling tree it must check that there is no infinite recursion being created. What mechanism does at the moment if Record A is Master and Parent of record B, and Record B is Master and Parent of record A then structure like A.Children[0] = B and B.Children[0] = A is being built. It all would work fine, but it has do be knockout.js bound and displayed as expandable list to users, which results in overflow when trying to display the tree.
Requirement is to detect such loops and do not create tree relationships.
Mechanism that would check if item is already in the tree I came up is:
function InTree(master, item) {
return $.inArray(item, $.map(master, function recurs(n) {
return ($.isArray(n) ? $.map(n, recurs) : n);
})) != -1;
}
if(!InTree(tree, record))
{
//attach
} else {
// get next record
}
Is there anything faster than InTree() function that would get me if item is in the tree?
Whole tree building algorithm is below (not that I think it is relevant but rather to avoid the comments 'show the code')
$(document).on('OnPreQuery', onTheMove.PageDataRoles, function (e, options) {
var isChildAttachmentQueued = true;
var knockoutContextName = options.knockoutContextName;
if (TreeEnabled(knockoutContextName)) {
var isModelReadyToAttachChildren = function () {
var isReady = false;
if (PageObj[knockoutContextName] != undefined) {
isReady = (PageObj[knockoutContextName]().length > 0) && isChildAttachmentQueued;
}
return isReady;
};
var businessComponent = eval(knockoutContextName);
var treeSettings = businessComponent.Tree;
treeSettings.knockoutContextName = knockoutContextName;
$(businessComponent).on('OnPreUIUpdate', function (e, options) {
if (isModelReadyToAttachChildren()) {
getChildrenForMasterRecordList({
parentTable: businessComponent.primaryTableName,
knockoutContextName: treeSettings.knockoutContextName,
parentIdColumn: treeSettings.ParentIdColumn,
masterIdColumn: treeSettings.MasterIdColumn
});
isChildAttachmentQueued = false;
}
});
}
});
function TreeEnabled(knockoutContextName) {
var isTreeEnabled = false;
try {
eval(knockoutContextName);
} catch (e) {
return isTreeEnabled;
}
var treeSettings = eval(knockoutContextName).Tree;
if (treeSettings && treeSettings.IncludeChildren) {
isTreeEnabled = true;
}
return isTreeEnabled;
}
function ComposeRecordsToTreeStructure(results, tableArray, columnArray, options) {
if (results.rows.length > 0) {
if (options.parentLayerIdList == undefined) {
options.parentLayerIdList = options.masterIdList;
}
if (options.orphans == undefined) {
options.orphans = [];
}
var knockoutContextName = options.knockoutContextName;
var childRecordIdArray = [];
if (options.runningOnOrphans) {
if (options.orphans.length > 0) {
for (var j = 0; j < options.orphans.length; j++) {
var rowRecord = options.orphans[j];
var rowRecordParentId = rowRecord[options.parentIdColumn];
var result = EstablishParentChildConnectionOnAlreadyProcessedNodes(rowRecord, rowRecordParentId, options.parentLayerIdList, knockoutContextName, childRecordIdArray, options);
if (result.hasEstablishedConnection) {
childRecordIdArray = result.childRecordIdArray;
}
}
options.orphans = $.grep(options.orphans, function (item) {
return $.inArray(item['Id'], childRecordIdArray) == -1;
});
}
} else {
for (var i = 0; i < results.rows.length; i++) {
var rowRecord = results.rows.item(i);
var rowRecordParentId = rowRecord[options.parentIdColumn];
if (rowRecord[options.parentIdColumn] == '' || rowRecord[options.masterIdColumn] == '' || rowRecord[options.masterIdColumn] == rowRecord['Id']) {
rowRecord.isInvalid = true;
} else if ($.inArray(rowRecord['Id'], options.masterIdList) != -1) {
masterRecordClone = $.grep(PageObj[knockoutContextName](), function (item) { return item.Fields.Id() == rowRecord['Id'] })[0];
if (masterRecordClone != undefined && masterRecordClone.Children) {
rowRecord.Children = masterRecordClone.Children;
}
}
if (rowRecord.isInvalid == true) {
if (rowRecord[options.masterIdColumn] != rowRecord['Id']) {
var result = EstablishParentChildConnection(rowRecord, rowRecord[options.masterIdColumn], options.parentLayerIdList, knockoutContextName, childRecordIdArray, options);
if (result.hasEstablishedConnection) {
childRecordIdArray = result.childRecordIdArray;
EstablishParentChildConnectionOnAlreadyProcessedNodes(rowRecord, rowRecordParentId, options.parentLayerIdList, knockoutContextName, childRecordIdArray, options);
}
}
} else {
var result = EstablishParentChildConnectionOnAlreadyProcessedNodes(rowRecord, rowRecordParentId, options.parentLayerIdList, knockoutContextName, childRecordIdArray, options);
if (result.hasEstablishedConnection) {
childRecordIdArray = result.childRecordIdArray;
} else {
var recordObject = AddIsExpandedProperty(rowRecord);
options.orphans.push(recordObject);
options.runningOnOrphans = true;
}
}
}
}
if (options.orphans.length > 0 && childRecordIdArray.length > 0) {
options.parentLayerIdList = childRecordIdArray;
ComposeRecordsToTreeStructure(results, tableArray, columnArray, options);
}
}
onTheMove.seleniumHelper.markPageAsLoaded();
}
function EstablishParentChildConnectionOnAlreadyProcessedNodes(rowRecord, rowRecordParentId, parentLayerIdList, knockoutContextName, childRecordIdArray, options) {
var result = EstablishParentChildConnection(rowRecord, rowRecordParentId, parentLayerIdList, knockoutContextName, childRecordIdArray);
if (result.hasEstablishedConnection) {
childRecordIdArray = result.childRecordIdArray;
} else {
var result = EstablishParentChildConnection(rowRecord, rowRecordParentId, childRecordIdArray, knockoutContextName, childRecordIdArray);
if (result.hasEstablishedConnection) {
childRecordIdArray = result.childRecordIdArray;
} else {
var matchingOrphans = $.grep(options.orphans, function (item) {
return item['Id'] == rowRecordParentId;
});
if (matchingOrphans.length > 0) {
AttachPassedChildRecord(rowRecord, matchingOrphans);
var result = {
hasEstablishedConnection: true
};
}
}
}
return {
childRecordIdArray: childRecordIdArray,
hasEstablishedConnection: result.hasEstablishedConnection
};
}
function EstablishParentChildConnection(rowRecord, rowRecordParentId, parentLayerIdList, knockoutContextName, childRecordIdArray) {
var hasEstablishedConnection = false;
var parentPosition = $.inArray(rowRecordParentId, parentLayerIdList);
if (parentPosition != -1) {
AttachChildRecordsToParents(rowRecord, parentLayerIdList[parentPosition], knockoutContextName);
childRecordIdArray = AddChildRecordsToNextParentList(rowRecord, childRecordIdArray);
childRecordIdArray.push(rowRecord['Id']);
hasEstablishedConnection = true;
}
return {
childRecordIdArray: childRecordIdArray,
hasEstablishedConnection: hasEstablishedConnection
};
}
function AddChildRecordsToNextParentList(childRecord, childRecordIdArray) {
if (childRecord.Children != undefined) {
for (var i = 0; i < childRecord.Children.length; i++) {
childRecordIdArray.push(childRecord.Children[i]['Id']);
if (childRecord.Children[i].Children != undefined) {
AddChildRecordsToNextParentList(childRecord.Children[i], childRecordIdArray);
}
}
}
return childRecordIdArray;
}
function RowsToListDataStructure(results) {
var array = [];
for (var i = 0; i < results.rows.length; i++) {
array.push(results.rows.item(i));
}
return array;
}
function AttachChildRecordsToParents(recordRow, id, knockoutContextName) {
var childTreeOptions = {
id: id,
knockoutContextName: knockoutContextName,
results: []
};
findObjectsInChildTreeById(childTreeOptions);
if (childTreeOptions.results.length > 0) {
AttachPassedChildRecord(recordRow, childTreeOptions.results);
}
}
function AttachPassedChildRecord(recordObject, pageObjParentResults) {
for (var i = 0; i < pageObjParentResults.length; i++) {
if (pageObjParentResults[i].Children == undefined) {
pageObjParentResults[i].Children = [];
}
if ($.grep(pageObjParentResults[i].Children, function (children) {
return children['Id'] == recordObject['Id'];
}).length == 0) {
recordObject = AddIsExpandedProperty(recordObject);
pageObjParentResults[i].Children.push(recordObject);
}
}
}
function AddIsExpandedProperty(recordObject) {
recordObject.IsExpanded = ko.observable(false);
return recordObject;
}
function findObjectsInChildTreeById(options) {
if (options.item == undefined) {
if (typeof PageObj[options.knockoutContextName] != 'undefined') {
for (var item in PageObj[options.knockoutContextName]()) {
findObjectsInChildTreeById({
item: PageObj[options.knockoutContextName]()[item],
id: options.id,
results: options.results
});
}
}
} else {
if (typeof options.item.Fields != 'undefined') {
if (options.item.Fields['Id']() == options.id)
options.results.push(options.item);
} else {
if (options.item['Id'] == options.id)
options.results.push(options.item);
}
if (options.item.Children != undefined) {
for (var item in options.item.Children) {
findObjectsInChildTreeById({
item: options.item.Children[item],
id: options.id,
results: options.results
});
}
}
}
}
function getChildrenForMasterRecordList(options) {
var parentTable = options.parentTable,
masterIdColumn = options.masterIdColumn,
parentIdColumn = options.parentIdColumn,
knockoutContextName = options.knockoutContextName,
masterIds = getParentIdsAndMastersOfParentsFromPageObj(knockoutContextName, masterIdColumn);
for (var item in PageObj[options.knockoutContextName]()) {
AddIsExpandedProperty(PageObj[knockoutContextName]()[item]);
}
var dbManager = new OnTheMoveDatabaseManager();
dbManager.queryDatabase({
statement: {
Tables: [{
Alias: parentTable,
JoinSpec: null,
JoinType: "",
Name: parentTable
}, {
Alias: "Record",
JoinSpec: "Record.Id = " + parentTable + ".Id",
JoinType: "INNER",
Name: "Record"
}],
WhereClause: parentTable + "." + masterIdColumn + " IN ('" + masterIds.join("','") + "') AND Record.RecordType ='" + parentTable + "'",
SelectFields: [{
IsAggregate: false,
Name: "*"
}],
DisablePaging: true,
OrderClause: "Record.Id"
},
knockoutContextName: knockoutContextName,
isObservable: false,
masterIdColumn: masterIdColumn,
masterIdList: masterIds,
parentIdColumn: parentIdColumn,
parentTable: options.parentTable,
success: function (results, tableArray, columnArray, options) {
ComposeRecordsToTreeStructure(results, tableArray, columnArray, options);
}
});
}
function getParentIdsAndMastersOfParentsFromPageObj(knockoutContextName, masterColumnName) {
var list = [];
if (typeof PageObj[knockoutContextName] != 'undefined') {
for (var item in PageObj[knockoutContextName]()) {
if ($.inArray(PageObj[knockoutContextName]()[item].Fields['Id'](), list) == -1) {
list.push(PageObj[knockoutContextName]()[item].Fields['Id']());
}
if (PageObj[knockoutContextName]()[item].Fields[masterColumnName]() != '' && $.inArray(PageObj[knockoutContextName]()[item].Fields[masterColumnName](), list) == -1) {
list.push(PageObj[knockoutContextName]()[item].Fields[masterColumnName]());
}
}
}
return list
}
function InTree(master, item) {
return $.inArray(item, $.map(master, function recurs(n) {
return ($.isArray(n) ? $.map(n, recurs) : n);
})) != -1;
}
it depends on your circumstances. if you're able to run code on add/creation of the tree you may simply create a node id array and do a check like
if(allNodes[searchKey])
//etc
This is a very specific solution of course but technically it'd be as fast as it could possibly be.