I'm new to angularjs and want to implement some hierarchy screen in which user can add a new group, child to that group and so on. (parent/child hierarchy)
Something like this
1 Admin
1.1 -----User Admin
1.1.1 ----------Tech Support Admin
1.1.1.1 --------------------Tech Support Team
1.2 ----------Login Admin
1.2.1 --------------------Profiles
1.3 -----Client Admin
1.3.1 ----------Client 1
1.3.2 ----------Client 2
2 Users
2.1 -----User 1
2.2 -----User 2
2.3 -----User 3
I've searched some tutorials and the only solution I found out relative to my problem is angular ui tree.
But I'm not satisfied with that because I have to add images/avatar with all nodes (parents/children), then have to assign some roles to each of them on the basis of their parent node. but ui-tree does not have any procedure to add customized nodes or child of any node.
Is there any better approach to do this? Any kind of help will be appreciated.
To implement following structure there is property name $parentNodesScope added to get parent index so i added
{{this.$parentNodesScope.$parentNodesScope.$index+1}}.
{{this.$parentNodesScope.$index+1}}.
{{$index+1}} {{node.title}}
1 Admin
1.1 -----User Admin
1.1.1 ----------Tech Support Admin
1.1.1.1 --------------------Tech Support Team
1.2 ----------Login Admin
1.2.1 --------------------Profiles
1.3 -----Client Admin
1.3.1 ----------Client 1
1.3.2 ----------Client 2
2 Users
2.1 -----User 1
2.2 -----User 2
2.3 -----User 3
Here is my jsfiddle link
jsfiddle
I rolled my own solution on something similar. I can't remember why I didn't go with ui-tree. What I needed was a way to recursively create views so that I could mimic a filesystem. Here's the plunk from when I was proofing it out. This should be simpler for you since you're not trying to split files and folders like I did.
With the recursion helper I was able to declare my data structure like this:
$scope.items = [
new File('item1', '/item1', 11, false),
new File('item2', '/item2', 22, true),
new File('item3', '/item3', 33, false),
new File('A Really Long File Name Should Go Here', '/item4', 44, false),
new Folder('Folder 1', '/folder1', [new File('item5', '/item5', 55, false)], false)
];
And I could render it using this:
<table class="table table-condensed table-responsive">
<tbody>
<tr>
<th></th>
<th>Name</th>
<th>Size</th>
<th></th>
</tr>
<tr ng-repeat="item in getFiles()">
<td class="minWidth4px">
<input type="checkbox" ng-model="item.isSelected" />
</td>
<td class="truncateName">
{{item.name}}
</td>
<td class="minWidth4px">{{item.size}}mb</td>
<td ng-show="item.canPreview()" class="minWidth4px">
<button class="btn" ng-click="openPreview(item)">Preview</button>
</td>
</tr>
<tr ng-repeat="item in getFolders()" ng-click="openFolder(item)">
<td class="minWidth4px">
<i ng-show="item.isOpen" class="fa fa-folder-open-o"></i>
<i ng-hide="item.isOpen" class="fa fa-folder-o"></i>
</td>
<td colspan="3">
<label>{{item.name}}</label>
<attachments ng-show="item.isOpen" items="item.items"></attachments>
</td>
</tr>
</tbody>
</table>
And here's the directive for the attachements:
var attachmentsLink = function($scope) {
$scope.openFolder = function(folder) {
folder.isOpen = !folder.isOpen;
console.log(folder);
};
$scope.getFiles = function() {
return $scope.items.filter(function(x) {
return x instanceof File;
});
};
$scope.getFolders = function() {
return $scope.items.filter(function(x) {
return x instanceof Folder;
});
};
};
var attachmentsController = function($scope, previewService){
$scope.openPreview = function(file) {
previewService.preview = file;
previewService.showPreview = true;
};
};
var attachments = function(RecursionHelper) {
return {
compile: function(element) {
return RecursionHelper.compile(element, attachmentsLink);
},
controller: attachmentsController,
restrict: 'E',
scope: {
items:'=',
},
templateUrl: 'attachments.html'
};
};
angular.module("app").directive("attachments", attachments);
I can't take credit for the recursion helper that is the meat of it. The recursion helper is here Hope this helps.
Long time.. let me post my solution here..may be it helps someone else..
So basically I did this with the help of angular-ui-tree with some custom changes to add avatar and links etc. here is html code;
<div class="panel-body">
<div class="col-sm-12">
<div ui-tree id="tree-root" ng-if="data.length > 0" data-drop-enabled="false" data-drag-enabled="false" data-nodrop-enabled="true">
<ol ui-tree-nodes ng-model="data">
<li ng-repeat="node in data" ui-tree-node ng-include="'nodes_renderer.html'" ></li>
</ol>
</div>
</div>
</div>
and this is my script;
<script type="text/ng-template" id="nodes_renderer.html">
<div ui-tree-handle class="tree-node tree-node-content">
<a class="btn btn-success btn-xs" ng-if="node.nodes && node.nodes.length > 0" data-nodrag ng-click="toggle(this)"><span
class="glyphicon"
ng-class="{
'glyphicon-chevron-right': collapsed,
'glyphicon-chevron-down': !collapsed
}"></span></a>
<a class="btn btn-xs" data-nodrag>
<img ng-src="{{node.image}}" class="img-avatar" alt="Avatar" height="35" width="35"></a>
{{node.title}}
<div class="dropdown pull-right ">
<a class="btn btn-primary btn-xs dropdown-toggle" data-toggle="dropdown" data-nodrag><span class="glyphicon glyphicon-th-list"></span></a>
<div class="dropdown-content dropdown-menu" data-nodrag>
<a ng-show = "flagCreateUserHierarchy" ng-click="btnAddUserClick(this)"><i class="fa fa-user"></i> Add User</a>
<a ng-show = "flagUpdateUserHierarchy" ng-click="btnEditClick(this)"><i class="fa fa-folder-open"></i> Edit</a>
<a ng-show="{{node.type}} <2 && flagUpdateUserHierarchy" ng-click="btnEditGroupClick(this)"><i class="fa fa-folder-open"></i> Edit Group Name</a>
<a ng-show = "flagUpdateUserHierarchy" ng-click="btnDeleteHierarchy(this)"><i class="fa fa-ban"></i> Delete</a>
</div>
</div>
and this is how it looks like...
I can further explain this whole procedure if anyone needs to understand.
Related
Our team is developing in ServiceNow and have a requirement to add rows from "Sending" table to "Receiving" table and delete rows from the "Receiving" table and return it back to the "Sending":
We've nailed down the adding portion of this exercise, but am having trouble getting the returning part to work correctly. Sometimes it will work completely fine. Other times, when we delete, it would uncheck the correct entry from the "Sending" table, but the entry would remain on the "Receiving" table.
On our "Sending" table, it is receiving the rootScope like this:
<tbody>
<tr ng-repeat="item in data.list track by item.sys_id">
<td ng-if="options.show_checkboxes">
<input type="checkbox"
ng-checked="item.isRowSelected"
ng-click="toggleSelection(item);" >
</td>
<td role="cell" class="pointer sp-list-cell"
ng-class="{selected: item.selected}"
ng-click="go(item.targetTable, item)"
ng-repeat="field in ::data.fields_array" data-field="{{::field}}"
data-th="{{::data.column_labels[field]}}">
<span ng-if="$first"
aria-label="${Open record}: {{::item[field].display_value}}"
role="link" tabindex="0">
{{::item[field].display_value | limitTo : item[field].limit}}
{{::item[field].display_value.length > item[field].limit ? '...' : ''}}
</span>
<span ng-if="!$first">
{{::item[field].display_value | limitTo : item[field].limit}}
{{::item[field].display_value.length > item[field].limit ? '...' : ''}}
</span>
</td>
</tr>
</tbody>
$scope.selectedItems = [];
$scope.toggleSelection = function(item){
item.isRowSelected = !item.isRowSelected;
if(item.isRowSelected==false){
$scope.allSelected=false;
if($scope.selectedItems.indexOf(item.sys_id)!==-1){
var add = $scope.selectedItems.indexOf(item.sys_id);
$scope.selectedItems.splice(add,1);
}
} else {
if($scope.selectedItems.indexOf(item.sys_id)==-1){
$scope.selectedItems.push(
item
);
$rootScope.$broadcast('moveItem', $scope.selectedItems);
}
}
}
$rootScope.$on('deleteItem', function(event, data) {
$scope.selectedItems = data;
});
In our "Receiving" table widget, our code looks like this:
<tbody>
<tr ng-repeat="item in data.list2 track by item.sys_id">
<td role="cell" class="pointer sp-list-cell"
ng-class="{selected: item.selected}"
ng-click="go(item.targetTable, item)"
ng-repeat="field in ::data.fields_array"
data-field="{{::field}}" data-th="{{::data.column_labels[field]}}">
<span ng-if="$first"
aria-label="${Open record}: {{::item[field].display_value}}"
role="link" tabindex="0">
{{::item[field].display_value | limitTo : item[field].limit}}
{{::item[field].display_value.length > item[field].limit ? '...' : ''}}
</span>
<span ng-if="!$first">
{{::item[field].display_value | limitTo : item[field].limit}}
{{::item[field].display_value.length > item[field].limit ? '...' : ''}}
</span>
</td>
<td>
<a href="javascript:void(0)" ng-click="deleteSelection(item);">
Remove
</a>
</td>
</tr>
</tbody>
$scope.deleteSelection = function(item){
item.isRowSelected =false;
var minus = $scope.data.list2.indexOf(item.sys_id);
$scope.data.list2.splice(minus, 1);
$rootScope.$broadcast('deleteItem', $scope.data.list2);
}
$rootScope.$on('moveItem', function(event, data) {
$scope.data.list2 = data;
$scope.data.row_count = data.length;
});
Avoid $rootScope.$on — it risks memory leaks
In the course of its operation, AngularJS adds and removes DOM with their attached directives and controllers. The listener functions added by $rootScope.$on are not automatically removed when a directive or controller is removed. This can result in memory leaks and undesired behavior.
To avoid memory leaks, add event listeners to the $scope of the controller, not $rootScope:
̶$̶r̶o̶o̶t̶S̶c̶o̶p̶e̶.̶$̶o̶n̶(̶'̶d̶e̶l̶e̶t̶e̶I̶t̶e̶m̶'̶,̶ ̶f̶u̶n̶c̶t̶i̶o̶n̶(̶e̶v̶e̶n̶t̶,̶ ̶d̶a̶t̶a̶)̶ ̶{̶
$scope.$on('deleteItem', function(event, data) {
$scope.selectedItems = data;
});
To avoid injecting $rootScope, use $scope.$root:
̶$̶r̶o̶o̶t̶S̶c̶o̶p̶e̶.̶$̶b̶r̶o̶a̶d̶c̶a̶s̶t̶(̶'̶m̶o̶v̶e̶I̶t̶e̶m̶'̶,̶ ̶$̶s̶c̶o̶p̶e̶.̶s̶e̶l̶e̶c̶t̶e̶d̶I̶t̶e̶m̶s̶)̶;̶
$scope.$root.$broadcast('moveItem', $scope.selectedItems);
I've created a simple app in AngularJS.
Please have a look: https://stackblitz.com/edit/angularjs-mcqdzw?embed=1&file=home/home.html&view=preview
Hope this helps.
I am currently working on a project in which, I am fetching the data from server and adding(pushing) in the array for further process. And its working great.
I face problem when I add an external data to the array with the data coming from server.
var quantity= ItemsValue[1];
$scope.product = [];
$http.get(___).success(function(data) {
$scope.greeting = data ;
$scope.product.push($scope.greeting);
}
I want to push "quantity" with the "$scope.greeting". I already tried different thing such as concatenation but failed.
I want data of array to be like this. For Example
$scope.product=[{ "greeting.name": "abc", "greeting.price": "50",
"quantity":"1" }]
Name and Price came from server and quantity in added as an extra data to Array.
<tbody >
<tr ng-repeat="greeting in product" ><!-- -->
<td class="cart_product">
<img src={{greeting.Image}} alt="book image" ></td>
<td class="cart_description">
<h4>{{greeting.Name}}</h4></td>
<td class="cart_price">
<p>Rs. {{greeting.Cost}}</p>
</td>
<td class="cart_quantity">
<div class="cart_quantity_button">
<a class="cart_quantity_up" href=""> + </a>
<input class="cart_quantity_input" type="text" name="quantity" value="Itemsquantity" autocomplete="off" size="2">
<a class="cart_quantity_down" href=""> - </a>
</div>
</td>
<td class="cart_total">
<p class="cart_total_price">Rs. {{greeting.Cost}}</p>
</td>
<td class="cart_delete">
<a class="cart_quantity_delete" ng-click="removeItem($index)"><i class="fa fa-times"></i></a>
</td>
</tr>
</tbody>
This is the code of client end.
Any way to push these things together...
You can just add it into the object by creating a new property
var quantity = ItemsValue[1];
$scope.product = [];
$http.get(___).success(function(data) {
$scope.greeting = data;
$scope.greeting.quantity = quantity;
$scope.product.push($scope.greeting);
}
I am using angularJs for developing an Hybrid Mobile App for IOS and Android. I am getting JSON data like :
[{"EventId":101,"Title":"No title","Date":"9/8/2015","Time":"12:00 AM","Location":""},{"EventId":120,"Title":"My First Event","Date":"9/15/2015","Time":"12:00 AM","Location":""}]
My question is that I have one button, click on that button I need to short my data based on current date. If i click on a button it should show me only that record that matched the current date.
I tried to follow this link but it is not working.
Code :
$scope.Schedule = [{"EventId":101,"Title":"No title","Date":"9/8/2015","Time":"12:00 AM","Location":""},{"EventId":120,"Title":"My First Event","Date":"9/15/2015","Time":"12:00 AM","Location":""}];
<ion-content>
<ul ng-repeat="member in Schedule">
<li class="item">
<div class="item" style="border-width: 0px; padding : 1px;">{{member.Title}}</div>
<div class="item" style="border-width: 0px; padding : 1px;">{{member.Location}}</div>
<div class="item" style="border-width: 0px; padding : 1px;">{{member.Time}}{{member.Date}}</div>
</li>
</ul>
</ion-content>
<ion-footer-bar align-title="left" class="bar-assertive">
<div class="list">
<a ng-click="setOrder()"> Show today's </a>
</div>
</ion-footer-bar>
Here's a working plnkr
Markup
<button ng-show="curDate == ''" type="button" ng-click="filterByCurDate()">Filter By Current Date</button>
<button ng-hide="curDate == ''" type="button" ng-click="curDate = ''">Clear Filter</button>
<table>
<thead>
<tr>
<th>EventId</th>
<th>Title</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="event in events | filter: {Date: curDate}">
<td>{{event.EventId}}</td>
<td>{{event.Title}}</td>
<td>{{event.Date}}</td>
</tr>
</tbody>
</table>
Controller Code
$scope.curDate = '';
$scope.filterByCurDate = function() {
var now = new Date();
$scope.curDate = $filter('date')(now, 'M/dd/yyyy');
};
$scope.events = [...];
If you want to order records based on date field use orderBy predicate instead of filter
Asc order
<ANY ng-repeat="record in records | orderBy:'Date'">..</ANY>
Desc order
<ANY ng-repeat="record in records | orderBy:'-Date'">..</ANY>
Angular DOC: orderBy
You could try something like this:
var today = new Date(),
jsonData = JSON.parse('[{"EventId":101,"Title":"No title","Date":"9/8/2015","Time":"12:00 AM","Location":""},{"EventId":120,"Title":"My First Event","Date":"1/29/2016","Time":"12:00 AM","Location":""}]');
today.setHours(0,0,0,0); //we don't need time to compare
jsonData.forEach(function(entry) {
entry.Date = new Date(entry.Date);
if (entry.Date.valueOf()===today.valueOf()){
console.log("Pass: "+entry);
}
});
Technologies: MVC5, ASP.NET 4.5, Angular 1.2.16
I am dynamically generating many parts of my cshtml view using Angular's ng-repeat statement.
I also want the ability to be able to email the page to a user.
I am trying to avoid recreating the entire Html on my controller.
My View:
<div class="col-md-12 form-horizontal" ng-controller="StatusListController">
<div class="adminButtons" ng-if="currentUser.netId == adminUser">
#*#Html.ActionLink("Send Email","Email","Home")*#
<button type="button" class="btn btn-primary" ng-click="statusEmail()">
Send Email
</button>
<button type="button" class="btn btn-danger" ng-click="statusReset()">
Reset
</button>
</div>
<div class="table-responsive">
<table class="table table-hover ">
<thead>
<tr class="tableHeaderRow">
<th class="col-md-3">
Name
</th>
<th class="col-md-7">
Workload Status
</th>
<th class="col-md-2">
Office
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="associate in associateList">
<td>
{{associate.AssociateName}}
</td>
<td>
<span class="col-md-3 tableLabel">
Short-Term:
</span>
<div class="col-md-9 tableValue"
ng-class="{
'statusBusy': associate.Status == 'busy',
'statusFlex': associate.Status == 'Flexible',
'statusFree': associate.Status == 'Available'
}">
{{associate.Status}}
</div>
<br />
<span class="col-md-3 tableLabel">
Mid-Term:
</span>
<div class="col-md-9 tableValue" ng-class="{
'statusBusy': associate.Status2 == 'busy',
'statusFlex': associate.Status2 == 'Flexible',
'statusFree': associate.Status2 == 'Available'
}">
{{associate.Status2}}
</div>
</td>
<td>
{{associate.Office}}
</td>
</tr>
</tbody>
</table>
</div>
I am calling my mvc controller method on an $html call from my angular controller.
Here's the mvc controller:
public virtual string RenderViewToString(ControllerContext controllerContext, string viewPath, string layoutPath, bool partial)
{
try
{
// first find the ViewEngine for this view
var viewEngineResult = partial
? ViewEngines.Engines.FindPartialView(controllerContext, viewPath)
: ViewEngines.Engines.FindView(controllerContext, viewPath, null);
if (viewEngineResult == null)
{
throw new FileNotFoundException("View cannot be found.");
}
// get the view and attach the model to view data
var view = viewEngineResult.View;
using (var sw = new StringWriter())
{
var viewPage = new ViewPage
{
ViewContext =
new ViewContext(controllerContext, view, controllerContext.Controller.ViewData, controllerContext.Controller.TempData, sw)
};
view.Render(viewPage.ViewContext, sw);
return sw.ToString();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
throw;
}
}
The html that it generates has the angular statements in it and not the final render of the view.
Any ideas on how I can get the angular rendered html?
My suggestion would be to just POST your angular-rendered HTML content from the client back to your server, where you server can forward it via email to the user. That way you don't have to do any sort of server-side rendering. You've already got the content rendered by the client, so you might as well use it.
Apart from that, the only other thing I can think of is using a headless browser to render the content. I'm not aware of any headless .NET browsers, but for Node.js there is Phantom.js, which is a headless browser that would render your angular content on the server.
Hope that helps.
Currently i have a backbone code like following
app.View.FriendRequestListViewModal = Backbone.View.extend( {
template: _.template($('#friend-request-list-modal').html()),
tagName: 'div',
initialize: function(){
this.render();
},
render: function() {
$(this.el).html(this.template({
friendRequestCollection: this.collection}));
return $(this.el);
},
});
and than I have a template like following
<script type="text/template" id="friend-request-list-modal">
<table class="table table-hover">
<# friendRequestCollection.each(function(user) { #>
<tr id="<#= user.get('username') #>">
<td>
<img class="pull-left avatar" src="/img/staff_avatar_profile.jpg"
</td>
<td>
<#= user.get('firstName') #> <#= user.get('lastName') #>
</td>
<td>
<div class="btn-group">
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#"><fmt:message key="user.request.action"/>
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><i class="icon-ok"></i><fmt:message key="user.add.accept.request"/></li>
<li><i class="icon-remove"></i><fmt:message key="user.add.reject.request"/></li>
</ul>
</div>
</td>
</tr>
<# }); #>
</table>
</script>
But now i wanted to create the same table using backbone because I have two buttons in this table which have the following models and I want to include these models using backbone. If u create the buttons using template than I think I will not be able to attach these models to those buttons. Do anybody have any suggestion..
app.Model.FriendRequestAcceptModel = Backbone.Model.extend({
url : function(){
return '/rest/friend/accept';
}
});
app.Model.FriendRequestCancelModel = Backbone.Model.extend({
url : function(){
return '/rest/friend/reject';
}
});
Majority people use like this ( same to here), but i prefer do like that: i make separate two template, firstly, i will render first, after then will call the second with collection, and would add second template's result to first.