I have the following markup:
<div class="modal fade" id="locationSearchModal" tabindex="-1" role="dialog">
<div class="modal-dialog narrow-modal" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Search for Locations</h4>
</div>
<div class="modal-body">
<div class="tree-container">
<section>
<h2>Browse for Locations</h2>
<div ui-tree="" data-drag-enabled="false" id="tree-root">
<ul ui-tree-nodes="" ng-model="data">
<li ng-repeat="item in data" ui-tree-node="" collapsed="!item.ItemsRetrieved" ng-include="item.Place || item.$hashkey == undefined ? 'parent_items_renderer' : 'terminal_item_renderer' " ></li>
</ul>
</div>
<script type="text/ng-template" id="parent_items_renderer">
<div ui-tree-handle class="tree-node tree-node-content" ng-class="{'tree-node-open': !collapsed}" ng-click="toggle(item); convertObjs(item)">
<i class="fa fa-caret-right" ng-class="{'fa-caret-right': collapsed, 'fa-caret-down': !collapsed}"></i>
<i class="fa fa-map-marker" ng-class="{'text-blue': !collapsed}"></i>
<span class="" ng-bind-html="item.PlaceName"></span>
</div>
<ul ng-if="item.Place != null" ui-tree-nodes ng-model="item.Place" ng-class="{hidden: collapsed}">
<li ng-repeat="item in item.Place" ui-tree-node collapsed="!item.ItemsRetrieved" ng-include="item.Place ? 'parent_items_renderer' : 'terminal_item_renderer' " on-finish-render="ngRepeatFinished"> </li>
</ul>
</script>
<script type="text/ng-template" id="terminal_item_renderer">
<div ui-tree-handle class="tree-node tree-node-content" ng-class="{'tree-node-open': !collapsed}" ng-click="addLocation(item)">
<a href title="Add Location"><span class="" ng-bind-html="item.PlaceName"></span></a>
</div>
</script>
</section>
</div>
</div>
</div>
</div>
</div>
The JSON data object that contains the location data is an hierarchical collection of Places:
{
"PlaceHierarchy":{
"Places":{
"Place":{
"PlaceID":"1000",
"PlaceTypeID":"5",
"PlaceName":"Company",
"AbbrName":"Company",
"Place":[
{
"PlaceID":"2000",
"PlaceTypeID":"4",
"PlaceName":"Region",
"AbbrName":"ThePlace",
"Place":[
{
"PlaceID":"3000",
"PlaceTypeID":"3",
"PlaceName":"SubRegion",
"AbbrName":"TheSubPlace",
"Place":[
{
"PlaceID":"4000",
"PlaceTypeID":"2",
"PlaceName":"SubSubRegion",
"AbbrName":"TheSubSubPlace",
"Place":[
{
"PlaceID":"5000",
"PlaceTypeID":"1",
"PlaceName":"Building",
"AbbrName":"Building",
"Place":[
{
"PlaceID":"5001",
"PlaceTypeID":"6",
"PlaceName":"Lobby",
"AbbrName":"Lobby"
},
{
"PlaceID":"5002",
"PlaceTypeID":"6",
"PlaceName":"Lobby 2",
"AbbrName":"Lobby2"
}
]
}
]
}
]
}
]
}
]
}
}
}
}
When I get that JSON back from the API, I need to process the data to make sure that all nodes are arrays. I do it like this:
$scope.processLocationNodes = function (nodes) {
for (var node in nodes) {
if (angular.isArray(node)) {
$scope.processLocationNodes(node);
} else {
$scope.convertObjs(node);
};
}
};
$scope.convertObjs = function (item) {
angular.forEach(item.Place, function (items) {
if (items != undefined && !angular.isString(items)) {
if (items.Place && !angular.isArray(items.Place)) {
var PlaceObj = items.Place;
items.Place = [];
items.Place.push(PlaceObj);
}
}
});
};
Now, when the modal is shown, the data properly displays and the tree works as expected. The only problem is, I want to default the tree to expand to the node of the Default Place of the user. I do that by the following logic:
The onFinishRender directive (debugging the code shows that this is hit):
app.directive('onFinishRender', function ($timeout) {
return {
link: function (scope, element, attr) {
if (scope.$last === true) {
$timeout(function () {
scope.$emit(attr.onFinishRender);
});
}
}
}
});
The ngRepeatFinished function is as follows:
$scope.$on('ngRepeatFinished', function (ngRepeatFinishedEvent) {
var rootScope = $scope.getRootNodesScope();
if (rootScope != undefined) {
rootScope.collapseAll();
$scope.expandNode($scope.defaultPlace);
}
});
$scope.getRootNodesScope = function() {
return angular.element(document.getElementById("tree-root")).scope().$nodesScope.childNodes()[0];
}
$scope.expandNode = function(nodeId) {
// We need to get the whole path to the node to open all the nodes on the path
var parentScopes = $scope.getScopePath(nodeId);
for (var i = 0; i < parentScopes.length; i++) {
parentScopes[i].expand();
}
};
$scope.getScopePath = function (nodeId) {
return $scope.getScopePathIter(nodeId, $scope.getRootNodesScope(), []);
};
$scope.getScopePathIter = function(nodeId, scope, parentScopeList) {
if (!scope) return null;
var newParentScopeList = parentScopeList.slice();
newParentScopeList.push(scope);
if (scope.$modelValue && scope.$modelValue.id === nodeId) return newParentScopeList;
var foundScopesPath = null;
var childNodes = scope.childNodes();
for (var i = 0; foundScopesPath === null && i < childNodes.length; i++) {
foundScopesPath = $scope.getScopePathIter(nodeId, childNodes[i], newParentScopeList);
}
return foundScopesPath;
};
Now, here's what my problem is:
First of all at the angular.element(document.getElementById("tree-root")).scope().$nodesScope.childNodes()[0] code, "childNodes()" is empty. No childNodes exist at all. Thus, the code has nothing to collapse or expand. I don't know why the childNodes collection is empty.
Second, once I figure that out, I can see what the actual NodeId is for a specific node and then be able to expand the tree to that node using the $scope.defaultPlace object.
Essentially, I just need to know why the childNodes collection is empty.
Related
I'm starting with AngularJS and I am using a controller variable to navigate an array of questions, and it is working when using nextQuestion function, index gets updated and the next question is shown in the view, but if I try to obtain the same value (index) in a different function, it always returns 0.
I have seen on other questions that you should use an object to contain the variable to not manipulate primitive types directly in the controller, but it still does not work.
My controller:
myApp.controller('SurveyController',['$scope','$http', '$location','$routeParams','surveyMetrics','DataService',function($scope,$http, $location,$routeParams,surveyMetrics,DataService){
console.log('LOADED QUIZ CONTROLLER');
var vm = this;
vm.scope = {
index: 0
};
vm.surveyMetrics = surveyMetrics;
vm.surveyQuestions = DataService.surveyQuestions;
vm.DataService = DataService;
/*
vm.getQuestions = function(){
$http.get('/api/questions').then(function(response){
$scope.questions = response.data;
});
}
*/
/*
vm.activateSurvey = function(){
surveyMetrics.changeState(true);
}
*/
vm.getCurrentIndex = function(){
return vm.scope.index;
}
vm.nextQuestion = function () {
console.log('NEXT QUESTION!');
console.log('NUMBER OF QUESTIONS: '+ vm.surveyQuestions.length);
var currentIndex = vm.getCurrentIndex();
var newIndex = currentIndex+1;
scope = {};
if (currentIndex == vm.surveyQuestions.length) {
newIndex = vm.surveyQuestions.length -1;
}
vm.scope.index = newIndex;
console.log('Inside Object: '+vm.scope)
console.log('vm.index'+vm.scope.index);
console.log('vm.indexFunction'+vm.getCurrentIndex());
}
/*
vm.previousQuestion = function () {
console.log('PREVIOUS QUESTION!');
console.log('NUMBER OF QUESTIONS: '+ vm.surveyQuestions.length);
if (vm.scope.index == 0) {
vm.scope.index = 0;
}else{
vm.scope.index--;
}
}
*/
vm.activeSurveyQuestion = function(questionId,index){
console.log('question id and index',questionId,index);
if (questionId == index) {
var navBtn = document.getElementById('navBtn_'+index);
navBtn.classList.add('active');
}
}
vm.navigateSurvey = function () {
var answerPane = document.getElementById('answer-pane');
document.onkeydown = function (e) {
console.log('INSIDE KEYDOWN: ')
e.preventDefault();
var pressedKey = e.keyCode;
console.log('PRESSED KEY IN SURVEY: ' + pressedKey);
if (pressedKey === rightArrow) {
console.log('survey - right arrow pressed');
document.getElementById('nextQuestionBtn').click();
console.log('FUCKING INDEX FML!: '+vm.getCurrentIndex()+' | '+vm.scope.index);
var questionType = DataService.getQuestionType(vm.scope.index);
console.log('Survey Controller: question type: '+questionType);
}
if (pressedKey === leftArrow) {
console.log('survey - left arrow pressed');
document.getElementById('previousQuestionBtn').click();
}
(...)
My View:
<!--Satisfaction Survey-->
<div ng-controller="SurveyController as survey" ng-init="survey.getSurvey();">
<!--
<p ng-repeat="question in survey.surveyQuestions" ng-show ="survey.surveyMetrics.surveyActive">
{{question.question}}
</p>
-->
<!--Survey Modal -->
<div class="modal fade" id="surveyModal" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="text-center"> Customer Satisfaction Survey</div>
<div class="modal-header">
<h4 class="modal-title">{{survey.surveyQuestions[survey.getCurrentIndex()].question}}</h4>
</div>
<div class="modal-body survey" id="answer-pane">
<div class="row">
<div class="col-sm-2 survey-left-arrow" ng-click="survey.previousQuestion();" id="previousQuestionBtn">
<p>‹</p>
</div>
<div class="col-sm-8">
<!-- <p ng-repeat="answer in survey.surveyQuestions[survey.index].answers">{{answer}}</p> -->
<p ng-repeat="answer in survey.surveyQuestions[survey.getCurrentIndex()].answers">
<button type="button" class="btn" id="answerId_{{survey.getCurrentIndex()}}"
ng-class="{'survey-check-box': (survey.surveyQuestions[survey.getCurrentIndex()].type !== 'SingleChoice'),
'survey-btn_{{($index+1)}}': (survey.surveyQuestions[survey.getCurrentIndex()].type === 'SingleChoice')}">
<input type="checkbox" ng-if="survey.surveyQuestions[survey.getCurrentIndex()].type !== 'SingleChoice'"> {{answer}}
</button>
</p>
</div>
<div class="col-sm-2 survey-right-arrow " ng-click="survey.nextQuestion();" id="nextQuestionBtn">
<p>›</p>
</div>
</div>
</div>
<div class="text-center">
<strong> <p>Question: {{survey.surveyQuestions[survey.scope.index].questionNum}} of {{survey.surveyQuestions.length}}</p> </strong>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
<!-- <nav aria-label="Survey navigation">
<ul class="pagination pagination-sm justify-content-center">
<div ng-repeat="question in survey.surveyQuestions" >
<li class="page-item">
<a class="page-link" id = "navBtn_$index" ng-click="survey.index = $index">{{question.id}}</a>
</li>
</div>
</ul>
</nav> -->
</div>
</div>
I would like for the controller to change the variable and the view to update accordingly
Thank you for your time and thank you in advance.
It's 'survey.scope.index' not 'survey.index' in your HTML. I think you may be unclear the difference between using 'this' and '$scope'. You're mixing the two together which is not necessary. I would suggest removing 'scope' and just reference it in your HTML as 'survey.index'.
I created new widget by cloning existing form widget in Service Portal (ServiceNow). Modified sys_id and table name in the URL (https://dev32223.service-now.com/aaportal/?id=departments&table=x_34334_aaaa_incident&sys_id=ee384830db2e32001cf8dec0cf9619de). Created new page with the widget and the resulting web page shows 'Record Not Found'
HTML:
<div ng-if="!data.isValid && !data.emptyStateTemplate" class="panel panel-default">
<div class="panel-body wrapper-lg text-center">
${Record not found}
</div>
</div>
<div ng-if="!data.isValid && data.emptyStateTemplate" class="panel-shift">
<div class="empty-state-wrapper panel panel-default" ng-include="data.emptyStateTemplate"></div>
</div>
<div ng-if="data.isValid" class="panel-shift">
<div class="" ng-if="!data.f._view.length && data.hideRelatedLists && data.emptyStateTemplate">
<div class="empty-state-wrapper panel panel-default" ng-include="data.emptyStateTemplate"></div>
</div>
<div class="" ng-if="!data.f._view.length && data.hideRelatedLists && !data.emptyStateTemplate">
<div class="panel panel-default">
<div class="panel-heading"><span class="panel-title">{{data.f.title}}</span> <span ng-if="options.showFormView == 'true' && data.f.view != ''">[{{data.f.view_title}} view]</span></div>
<div class="panel-body wrapper-lg text-center">
${No elements to display}
</div>
</div>
</div>
<div class="panel panel-default" ng-if="data.f._view.length || !data.hideRelatedLists" >
<div class="panel-heading" ng-if="data.f.title.length" sp-context-menu="getUIActionContextMenu(event)">
<span class="dropdown m-r-xs" ng-if="(data.isAdmin || getUIActions('context').length > 0) && options.omitHeaderOptions != 'true'">
<span class="dropdown-toggle glyphicon glyphicon-menu-hamburger" style="line-height: 1.4em" id="adminMenu" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"></span>
<ul class="dropdown-menu" aria-labelledby="adminMenu">
<li ng-if="::data.isAdmin">${Open in platform}</li>
<li ng-if="::data.isAdmin" class="dropdown-header">${Configure}</li>
<li ng-if="::data.isAdmin">${Form Layout}</li>
<li ng-if="::data.isAdmin">${Related Lists}</li>
<li ng-if="::data.isAdmin">${UI Policies} <span class="badge pull-right" ng-if="f.policy.length">{{f.policy.length}}</span></li>
<li ng-if="::data.isAdmin">${Client Scripts} <span class="badge pull-right" ng-if="adminMenu.getClientScriptCount()">{{adminMenu.getClientScriptCount()}}</span></li>
<li ng-if="getUIActions('context').length > 0 && data.isAdmin" role="separator" class="divider"></li>
<li ng-repeat="action in getUIActions('context')">{{action.name}}</li>
<li ng-if="::data.isAdmin || getUIActions('context').length > 0" role="separator" class="divider"></li>
<li><a target="_new" href="/{{data.f.table}}.do?PDF&sys_id={{data.sys_id}}&sysparm_view={{data.f.view}}">${Export to PDF}</a></li>
<li><a target="_new" href="/{{data.f.table}}.do?PDF&landscape=true&sys_id={{data.sys_id}}&sysparm_view={{data.f.view}}">${Export to PDF (landscape)}</a></li>
</ul>
</span>
<span class="panel-title">{{data.f.title}}</span> <span ng-if="options.showFormView == 'true' && data.f.view != ''">[{{data.f.view_title}} view]</span>
<div ng-if="attachmentHandler && data.canAttach" title="{{::data.addAttachmentMsg}}" class="pull-right attachment-button">
<sp-attachment-button></sp-attachment-button>
</div>
</div>
<div class="panel-body">
<!-- performance debug -->
<div ng-if="data.show_sql">
<div class="comment">
<span ng-if="data.f._perf.sql_count">${SQL Statements {{data.f._perf.sql_count}}}, </span>
<span>${Time {{data.f._perf.time}}}</span>
</div>
<div ng-repeat="s in data.f._perf.sql" class="{{s.type}}">
{{s.statement}}
</div>
</div>
<!-- attachments -->
<sp-attachment-manager table="data.table" sys-id="data.f._attachmentGUID" omit-edit="!data.canAttach"></sp-attachment-manager>
<!-- form -->
<div>
<sp-model form_model="data.f" mandatory="mandatory"></sp-model>
</div>
<!-- UI Action Links -->
<div ng-if="getUIActions('link').length > 0">
<label style="margin: 0;">${Related Links}</label>
<div ng-repeat="action in getUIActions('link')">
<a href ng-click="triggerUIAction(action)">{{action.name}}</a>
</div>
</div>
<!-- related lists -->
<div ng-if="!data.hideRelatedLists">
<label style="margin: 0">${Related Lists}</label>
<div style="margin-bottom: 7px; padding-bottom: 7px; border-bottom: 1px solid #f5f5f5;">
<span ng-repeat="rl in data.f._related_lists" ng-if="rl.visible">
<a ng-if="rl.type != 'REL'" href="?id=lf&table={{rl.table}}&filter={{rl.field}}%3D{{data.f.sys_id}}&view={{data.f.view}}" ng-click="openRelatedList($event, {id: 'lf', table: '{{rl.table}}', filter: '{{rl.field}}%3D{{data.f.sys_id}}'})">{{rl.plural}}
<span class="label label-as-badge label-primary" ng-if="rl.count">{{rl.count}}</span>
</a>
<a ng-if="rl.type == 'REL'" href="?id=lf&table={{rl.table}}&relationship_id={{rl.relationship_id}}&apply_to={{rl.apply_to}}&apply_to_sys_id={{rl.apply_to_sys_id}}&view={{data.f.view}}" ng-click="openRelatedList($event, {id: 'lf', table: '{{rl.table}}', apply_to: '{{rl.apply_to}}', apply_to_sys_id: '{{rl.apply_to_sys_id}}', relationship_id: '{{rl.relationship_id}}'})">{{rl.label}}
<span class="label label-as-badge label-primary" ng-if="rl.count">{{rl.count}}</span>
</a>
<span ng-if="!$last" style="padding-left: .5em; padding-right: .5em;"> | </span>
</span>
</div>
</div>
</div>
<div class="panel-footer">
<button ng-mousedown="triggerUIAction(action)" ng-repeat="action in getUIActions('button')" class="btn btn-default action-btn">{{action.name}}</button>
<span>{{status}}</span>
<button ng-if="getPrimaryAction()" type="submit" ng-mousedown="triggerUIAction(getPrimaryAction())" class="btn btn-primary action-btn pull-right">${Save} <span ng-if="saveButtonSuffix">(${{{saveButtonSuffix}}})</span></button>
<div style="clear: both;"></div>
<div ng-if="mandatory.length" class="alert alert-info" style="margin-top: .5em">
<span ng-if="mandatory.length > 0">${Required information} </span>
<span ng-repeat="f in mandatory" class="label label-danger" style="margin-right: .5em; display: inline-block;">{{f.label}}</span>
</div>
</div>
</div>
</div>
Client Script:
function ($scope, $rootScope, $timeout, spUtil, $location, $window, nowAttachmentHandler) {
$scope.mandatory = [];
$scope.data.show_sql = false;
$scope.saveButtonSuffix = spUtil.getAccelerator('s');
$scope.adminMenu = {
encodedPageUrl: encodeURIComponent($location.url()),
getClientScriptCount: function() {
var count = 0;
if ($scope.data.f.client_script) {
count += $scope.data.f.client_script.onChange.length;
count += $scope.data.f.client_script.onLoad.length;
count += $scope.data.f.client_script.onSubmit.length;
}
return count;
}
};
$scope.getUIActions = function(type) {
if ($scope.data.disableUIActions)
return [];
if (type) {
return $scope.data.f._ui_actions.filter(function(action) {
//We handle the primary action button separately.
return !action.primary && action['is_' + type];
});
} else {
return $scope.data.f._ui_actions;
}
}
$scope.getPrimaryAction = function() {
var primaryActions = $scope.data.f._ui_actions.filter(function(action) {
return action.primary;
});
return (primaryActions.length) ? primaryActions[0] : null;
}
$scope.getUIActionContextMenu = function(event) {
var menu = [];
if (event.ctrlKey)
return menu;
var contextActions = $scope.getUIActions('context');
contextActions.forEach(function(action) {
menu.push([action.name, function() {
$scope.triggerUIAction(action);
}]);
});
if (contextActions.length > 0)
menu.push(null);
menu.push([$scope.data.exportPDFMsg, function() {exportPDF("");}]);
menu.push([$scope.data.exportPDFLandMsg, function() {exportPDF('true');}]);
return menu;
}
function exportPDF(landscape) {
$window.open("/" + $scope.data.f.table + ".do?PDF&landscape=" + landscape + "&sys_id=" + $scope.data.sys_id + "&sysparm_view=" + $scope.data.f.view);
}
//trigger the primary UI Action on save (if there is one)
var deregister = $scope.$on('$sp.save', function() {
var primaryAction = $scope.getPrimaryAction();
if (primaryAction)
$scope.triggerUIAction(primaryAction);
});
$scope.$on('$destroy', function() {deregister()});
$scope.triggerUIAction = function(action) {
if ($scope.data.disableUIActions)
return;
if (g_form) {
$timeout(function() {
g_form.submit(action.action_name || action.sys_id);
});
}
}
$scope.$on("spModel.uiActionComplete", function(evt, response) {
var sysID = (response.isInsert) ? response.sys_id : $scope.data.sys_id;
loadForm($scope.data.table, sysID).then(constructResponseHandler(response));
});
function constructResponseHandler(response) {
return function() {
var message;
var eventName = "sp.form.record.updated";
if (response.isInsert) {
message = $scope.data.recordAddedMsg;
var search = $location.search();
search.sys_id = response.sys_id;
search.spa = 1;
$location.search(search).replace();
} else
message = $scope.data.updatedMsg;
$scope.data.hideRelatedLists = hideRelatedLists();
$scope.$emit(eventName, $scope.data.f._fields);
$rootScope.$broadcast(eventName, $scope.data.f._fields);
$scope.status = message;
spUtil.addTrivialMessage(message);
$timeout(clearStatus, 2000);
}
}
var ctrl = this;
// switch forms
var unregister = $scope.$on('$sp.list.click', onListClick);
$scope.$on("$destroy", function() {
unregister();
})
function onListClick(evt,arg) {
loadForm(arg.table, arg.sys_id);
}
function loadForm(table, sys_id){
var f = {};
//$scope.data.table = f.table = 'x_19668_halo_incident';
//$scope.data.sys_id = f.sys_id ='ee384830db2e32001cf8dec0cf9619de';
$scope.data.table = f.table = table;
$scope.data.sys_id = f.sys_id = sys_id;
f.view = $scope.data.view;
return $scope.server.update().then(setupAttachmentHandler);
}
function openRelatedList(e, queryString){
// todo: Open this in a modal
$location.search(queryString);
e.preventDefault();
}
$scope.$on('spModel.fields.rendered', function() {
if (ctrl.panels)
ctrl.panels.removeClass('shift-out').addClass('shift-in');
});
var g_form;
$scope.$on('spModel.gForm.initialized', function(e, gFormInstance) {
if (gFormInstance.getTableName() == $scope.data.f.table)
g_form = gFormInstance;
});
// Show or hide related lists
$scope.$watch('data.f._related_lists', function(){
$scope.data.hideRelatedLists = hideRelatedLists();
}, true);
function hideRelatedLists() {
if (!$scope.data.f._related_lists)
return true;
if ($scope.options.hideRelatedLists == true)
return true;
if ($scope.data.sys_id == '-1')
return true;
// If all related lists are visible=false then hide
if ($scope.data.f._related_lists.length > 0) {
for (var i in $scope.data.f._related_lists) {
var list = $scope.data.f._related_lists[i];
if (list.visible) {
return false;
}
}
}
return true;
}
function clearStatus() {
$scope.status = "";
}
function setupAttachmentHandler(){
$scope.attachmentHandler = new nowAttachmentHandler(appendSuccess, appendError);
$timeout(function() {
var sizeLimit = 1024 * 1024 * 24; // 24MB
$scope.attachmentHandler.setParams($scope.data.table, $scope.data.f._attachmentGUID, sizeLimit);
});
$scope.$on('dialog.upload_too_large.show', function(e){
console.log($scope.data.largeAttachmentMsg);
spUtil.addErrorMessage($scope.data.largeAttachmentMsg);
});
}
setupAttachmentHandler();
function appendSuccess() {
spUtil.addTrivialMessage($scope.data.attachmentUploadSuccessMsg);
$scope.$broadcast("sp.attachments.update", $scope.data.f._attachmentGUID);
}
function appendError(error) {
$scope.errorMessages.push(error);
}
}
Server Script:
// form functionality - URL parameter driven
(function($sp, input, data, options, gs)
{
/* "use strict"; -linter issues */
// populate the 'data' variable
data.attachmentUploadSuccessMsg = gs.getMessage("Attachment upload was successful");
data.recordAddedMsg = gs.getMessage("Record Added");
data.updatedMsg = gs.getMessage("updated_uppercase");
data.exportPDFMsg = gs.getMessage("Export to PDF");
data.exportPDFLandMsg = gs.getMessage("Export to PDF (landscape)");
data.addAttachmentMsg = gs.getMessage("Add an attachment");
data.largeAttachmentMsg = gs.getMessage("Attached files must be smaller than {0} - please try again", "24MB");
data.isAdmin = true;
data.emptyStateTemplate = options.empty_state_template;
data.disableUIActions = options.disableUIActions || false;
data.hideRelatedLists = options.hideRelatedLists || false;
if (input) {
data.table = input.table;
data.sys_id = input.sys_id;
data.view = input.view;
var result = {};
if (input._fields)
result = $sp.saveRecord(input.table, input.sys_id, input._fields);
if (input.sys_id == '-1'){
data.sys_id = result.sys_id;
data.isNewRecord = true;
}
} else {
data.table = $sp.getParameter("t") || $sp.getParameter("table") || $sp.getParameter("sl_table") || options.table;
data.sys_id = $sp.getParameter("sys_id") || $sp.getParameter("sl_sys_id") || options.sys_id;
data.view = $sp.getParameter("v") || $sp.getParameter("view") || options.view; // no default
}
data.query = $sp.getParameter("query") || options.query;
data.f = {};
if (!data.table)
return;
//if (!GlideTableDescriptor.isValid(data.table))
//return;
if (!data.sys_id)
return;
gs.info("data.table, data.sys_id 3:");
var rec = $sp.getRecord(data.table, data.sys_id); gs.info("data.table, data.sys_id 31:");
data.isValid = rec.isValid() || data.sys_id == "-1"; gs.info("data.table, data.sys_id 32:");
gs.info("data.table, data.sys_id 4:");
if (!data.isValid)
return;
gs.info("data.table, data.sys_id :"+data.table+ data.sys_id);
data.table = rec.getRecordClassName();
data.tableHierarchy = GlideDBObjectManager.getTables(data.table).toArray().join();
data.canWrite = rec.canWrite();
data.canAttach = data.canWrite && gs.hasRole(gs.getProperty('glide.attachment.role')) && !GlideTableDescriptor.get(data.table).getED().getBooleanAttribute("no_attachment");
data.f = $sp.getForm(data.table, data.sys_id, data.query, data.view);
// Activity formatter is hardcoded to set specific options
for (var f in data.f._formatters) {
var fm = data.f._formatters[f];
if (fm.formatter == "activity.xml") {
fm.hardcoded = true;
fm.widgetInstance = $sp.getWidget('widget-ticket-conversation',
{table: data.table,
sys_id: data.sys_id,
includeExtended: true,
title: "${Activity}",
placeholder: "${Add a comment}",
btnLabel: "${Post}"});
} else
fm.widgetInstance = $sp.getWidget(fm.widget, data);
}
})($sp, input, data, options, gs);
It looks like the control is not passing the line var rec = $sp.getRecord(data.table, data.sys_id); I can not figure out the issue, but I have an alternate solution. You can use iframes (shown below) to show form or list of records.
Mark it as answer if this answers your question.
Left hand side of the page is displaying list of task force.
On click of the list item related data is to be displayed on right hand side.
When I click on the list item, first time it works fine. It displays the task force name as a header in right hand side panel. When I click on another list item it gives TypeError: v2.CurrentTaskForce is not a function
var VirtualDir = GetVirtualDirectory();
angular.module('MyApp',[])
.controller('TaskForceController', function ($scope, TaskForceService) { // inject taskforce service
$scope.TaskForceList = null;
//$scope.CurrentTaskForce = {}
TaskForceService.GetTaskForceList().then(function (d) {
$scope.TaskForceList = d.data;
}, function () {
alert('failed');
});
$scope.CurrentTaskForce = function (item) {
angular.forEach($scope.TaskForceList, function (value, index) {
value.IsActive = false ;
})
item.IsActive = true;
alert("s");
$scope.CurrentTaskForce = item;
}
})
.factory('TaskForceService', function ($http) { //here factory is created which is a populer way to create and configure services
var fac = {};
fac.GetTaskForceList = function () {
return $http.get(VirtualDir + '/TaskForce/GetMyTaskForce/');
}
return fac;
});
<div class="container-fluid" ng-controller="TaskForceController as tf">
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar" >
<%-- <li class="active">Overview <span class="sr-only">(current)</span></li>--%>
<li ng-repeat="item in TaskForceList" ng-class="{active: item.IsActive == true}" ng-click="CurrentTaskForce(item)" ><a href="#" >{{item.TaskForce}}</a></li>
</ul>
</div>
<div class="col-sm-9 co-md-9" style="left:20%">
<div class="panel panel-default" ">
<div class="panel-heading">
<p class="panel-title">{{CurrentTaskForce.TaskForce}}</p>
<!--ng-repeat="curritem in CurrentTaskForce"-->
</div>
</div>
</div>
</div>
</div>
While copying item to CurrentTask force instead of
$scope.CurrentTaskForce = item;
I used
angular.copy(item, $scope.CurrentTaskForce);
It is happening because CurrentTaskForce is defined as a function and a variable in same controller. Please use a different name for either.
I have an angular application with tabs. Those tabs show and hide the div content using the ng-show directive. Each div contains inside some canvas showing ChartJS charts.
When i swipe from tab to another, i find that my charts are not rendered until y relaod the page or make another request to my function in order to reload the charts querying my server, eventhough all the data is already loaded by a $promise.
Here, my charts are correctly rendered...
But when i change my tab without forcing a reload (the data is already loaded), this is what happens...
This is my HTML
<section style="overflow-y:hidden" class="bg-white scroller-v" ng-init="AskForToggle()">
<div class="tab-nav clearfix">
<ul class="side-padding-3x">
<li data-ng-class="activeSubMenu('Actividades')">
<a class="size-12x" data-ng-click="Show('Actividades')">Actividades</a>
</li>
<li data-ng-class="activeSubMenu('Paginas')">
<a class="size-12x" data-ng-click="Show('Paginas')">Compromiso</a>
</li>
<li data-ng-class="activeSubMenu('Videos')">
<a class="size-12x" data-ng-click="Show('Videos')">Videos</a>
</li>
</ul>
</div>
<div class="col col-unpadded col-lg-2 col-md-3 col-sm-12 col-xs-12 side-menu">
<header>Fechas</header>
<ul class="list">
<li><input type="date" ng-model="analyticsDateDesde" ng-change="ValidateDateDesde(analyticsDateDesde)" /></li>
<li><input type="date" ng-model="analyticsDateHasta" ng-change="ValidateDateHasta(analyticsDateHasta)" /></li>
<li><input type="button" ng-click="UpdateAnalytics()" value="Actualizar Fechas" style="color:white; background-color:#3c8dbc;border:#3c8dbc" /></li>
</ul>
<header>Alumnos</header>
<ul class="list">
<li data-ng-repeat="user in users">
<a data-ng-class="activeNav(user)" data-ng-click="$parent.selectedUser = user">{{user.name}} {{user.lastName}}</a>
</li>
</ul>
</div>
<div id="divActividades" class="col col-unpadded col-lg-10 col-md-9 col-sm-12 col-xs-12" style="overflow-y: scroll; overflow-x:hidden;height: 100%;">
Some charts
</div>
<div id="divPaginas" class="col col-unpadded col-lg-10 col-md-9 col-sm-12 col-xs-12" style="overflow-y: scroll; overflow-x:hidden;height: 100%;">
Some charts
</div>
<div id="divVideos" class="col col-unpadded col-lg-10 col-md-9 col-sm-12 col-xs-12" style="overflow-y: scroll; overflow-x:hidden;height: 100%;">
Some charts
</div>
And this my angular controller
appFlipped.controller("ClassTraceability", ["$rootScope", "$scope", "Courseware", "$timeout", "$window", function (n, t, i, to, window) {
t.GetTypeClass = function (traza) {
if (traza.tipoAccion == 'Video')
return 'cd-timeline-img cd-movie';
else if (traza.tipoAccion == 'Problem')
return 'cd-timeline-img cd-picture';
else
return 'cd-timeline-img cd-location';
}
n.menuData = utils.courseMenu();
t.activeNav = function (n) {
return {
active: t.selectedUser && t.selectedUser.id == n.id
}
}
t.users = [];
t.selectedUser = null;
t.timeOnPlatform = null;
t.timeOnPlatformPerDayComparison = null;
t.timeOnPlatformPerDay = null;
i.init(n.routeData.classId).then(function () {
i.users.queryClass().$promise.then(function (n) {
t.users = n;
n.length && (t.selectedUser = n[0]);
})
});
t.$watch("selectedUser", function (n) {
n != null && t.loadTraceability();
});
t.UpdateAnalytics = function () {
t.loadTraceability();
}
t.loadTraceability = function () {
if (t.selectedUser != null) {
var p = {
userId: t.selectedUser.id,
courseURL: n.rutaParaAnalytics,
fechaDesde: t.analyticsDateDesde,
fechaHasta: t.analyticsDateHasta
};
i.traceability.get(p).$promise.then(function (n) {
t.Traceability = n.traceability;
t.showTimeline = t.Traceability.length > 0 ? true : false;
t.labelsTimeOnPlatform = n.timeOnPlatform[0];
t.dataTimeOnPlatform = n.timeOnPlatform[1];
t.loadPageActivity();
t.labelsTimeOnPlatformPerDay = n.timeOnPlatformPerDay[0];
t.dataTimeOnPlatformPerDay = n.timeOnPlatformPerDay[1];
t.loadPageActivityPerDay();
t.labelsTimeOnPlatformPerDayComparison = (n.timeOnPlatformPerDayComparison[0])[0];
t.dataTimeOnPlatformPerDayComparisonClass = (n.timeOnPlatformPerDayComparison[0])[1];
t.dataTimeOnPlatformPerDayComparisonStudent = (n.timeOnPlatformPerDayComparison[1])[1];
t.loadPageActivityComparison();
t.totalVideoCount = n.genericVideoAnalytics[0];
t.userTotalVideoCount = n.genericVideoAnalytics[1];
t.totalMinutesVideosCount = n.genericVideoAnalytics[2];
t.usertotalMinutesVideosCount = n.genericVideoAnalytics[3];
t.loadGenericVideoAnalytics();
t.videoTimeLabels = n.videoTime[0];
t.videoTimeData = n.videoTime[1];
t.loadVideoTime();
t.videoTimePerDayLabels = n.videoTimePerDay[0];
t.videoTimePerDayData = n.videoTimePerDay[1];
t.loadVideoTimePerDay();
t.videoTimePerDayComparisonLabels = (n.videoTimePerDayComparison[0])[0];
t.videoTimePerDayComparisonClass = (n.videoTimePerDayComparison[0])[1];
t.videoTimePerDayComparisonUser = (n.videoTimePerDayComparison[1])[1];
t.loadVideoTimePerDayComparison();
});
}
};
t.PaginaVisible = 'Actividades';
t.activeSubMenu = function (pagina) {
if (t.PaginaVisible == pagina)
return 'active';
else
return '';
}
t.Show = function (pagina) {
if (pagina == 'Actividades') {
angular.element("#divActividades")[0].style.display = 'block';
angular.element("#divPaginas")[0].style.display = 'none';
angular.element("#divVideos")[0].style.display = 'none';
t.PaginaVisible = 'Actividades';
}
if (pagina == 'Paginas') {
angular.element("#divActividades")[0].style.display = 'none';
angular.element("#divPaginas")[0].style.display = 'block';
angular.element("#divVideos")[0].style.display = 'none';
t.PaginaVisible = 'Paginas';
}
if (pagina == 'Videos') {
angular.element("#divActividades")[0].style.display = 'none';
angular.element("#divPaginas")[0].style.display = 'none';
angular.element("#divVideos")[0].style.display = 'block';
t.PaginaVisible = 'Videos';
}
}
}]);
The most wired thing is that one of all the charts is rendered!! Have anyone face the same problem?
Regards
A similar issue had been reported here :
https://github.com/jtblin/angular-chart.js/issues/29
If the chart is contained in a div that is hidden and then appear on screen
it won't render correctly (encountering the same issue right now!). Which is the case for your charts in the tabs hidden tabs with ng-show directives. A workaround would be to redraw the chart on changing tab.
This should be achievable via the myChart.update() method.
And it could be triggered in your Show method for instance.
I will try different solutions for my part and will update this answer accordingly. Hope it could help a little!
I want to store the users vote's inside a cookie, the problem is that inside the ng-repeat I have a value called session.upVoteCount. But it is supposed to be a separate value for each event list item. Is it possible to store each upVoteCount separately and then retrieve them separately again?
<li ng-repeat="session in event.sessions | filter:query | orderBy:sortorder" class="span11">
<div class="row session">
<div class="col-sm-1 well votingWidget">
<div class="votingButton" ng-click="upVoteSession(session)">
<span class="glyphicon glyphicon-arrow-up"></span>
</div>
<div class="badge badge-inverse">
<div>{{session.upVoteCount}}</div>
</div>
<div class="votingButton" ng-click="downVoteSession(session)">
<span class="glyphicon glyphicon-arrow-down"></span>
</div>
</div>
</div>
</li>
and in my controller I have this:
$scope.upVoteSession = function(session) {
session.upVoteCount++;
};
$scope.downVoteSession = function(session) {
session.upVoteCount--;
};
First, I don't recommend to use term 'session', but 'votes'. However, it's your call.
I simplify your problem in this example
http://plnkr.co/edit/l7tQRbuOtEDJetY5eTsf?p=preview
Javascript:
function MyCtrl($scope) {
$scope.votes = {};
$scope.vote = function(key, val) {
$scope.votes[key] = $scope.votes[key] || 0;
$scope.votes[key]+= val;
};
}
Html:
<li ng-repeat="no in [1,2,3,4,5]">
{{no}} : {{votes[no]}} <br/>
upvote
downvote
</li>
Hi guys I solved it myself, I could not get it to work with JSfiddle so I have uploaded the entire thing. Click on server.bat and browser to localhost:8000/eventdetails.html and you will see it working.
https://mega.co.nz/#!1d9yiYiA!zTzdztLAmhVDVYOvvVLINETI2bo_WjxCBteWYm2VUKc
controller:
eventsApp.controller('EventController',
function EventController($scope, $cookieStore, eventData) {
$scope.sortorder = 'name';
var ape = eventData.getEvent();
ape.then(function (banana) {
$scope.event = banana;
angular.forEach(banana.sessions, function (value, key) {
var storecookie = ($cookieStore.get(value.name));
if (typeof storecookie !== "undefined") {
value.upVoteCount = storecookie;
}
});
});
$scope.upVoteSession = function (session) {
session.upVoteCount++;
$cookieStore.put(session.name, session.upVoteCount);
};
$scope.downVoteSession = function (session) {
session.upVoteCount--;
$cookieStore.put(session.name, session.upVoteCount);
};
}
);