How to create a table view Using Backbone collection - backbone.js

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.

Related

Adding and deleting rows from one table to another - AngularJS

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.

Hierarchy implementation in angularjs

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.

Adding form values to a table with backbone and handlebars

The scenario is to add the values entered in form fields into a table on click of Add button. I am new to this both and not sure how data binding works.
My initial html is
<table class="table table-bordered">
<thead>
<tr>
<th>Model</th>
<th>Brand</th>
<th>Year</th>
<th>Action</th>
</tr>
<tr>
<td><input class="form-control" id="modelname"></td>
<td><input class="form-control" id="brandname"></td>
<td><input class="form-control" id="yearname"></td>
<td><button class="btn btn-primary add">Add</button></td>
</tr>
</thead>
<tbody class="product-list">
</tbody>
</table>
</div>
<script type="text/x-handlebars-template" id="product-template">
{{#each []}}
<tr>
<td>{{ model }}</td>
<td>{{ brand }}</td>
<td>{{ year }}</td>
<td><div class="btn btn-primary">Edit</div> <div class="btn btn-danger">Delete</div></td>
</tr>
{{/each}}
</script>
I messed up in js for purpose of using handlebars as
var Product=Backbone.Model.extend({
model:'',
brand:'',
year:''
});
var ProductCollection=Backbone.Collection.extend({
model:Product
});
var modelname= document.getElementById('modelname').value;
var brandname=document.getElementById('brandname').value;
var yearname= document.getElementById('yearname').value;
var ProductView = Backbone.View.extend({
el: '.product-list',
tagName: 'tr',
events:{
"click .add": "create"
},
initialize:function(){
this.render();
},
render:function()
{
var source=$('#product-template').html();
var template=Handlebars.compile(source);
var html=template(this.products.toJSON());
},
create: function(e){
var product=new Product({
model:modelname,
brand:brandname,
year:yearname
})
console.log(product.toJSON);
products.add(product);
modelname="";
yearname="";
brandname="";
}
});
var products=new ProductCollection();
Share me an idea how to proceed. I don't get an error and at the same time, nothing happens! I am very new to backbone. Please tolerate blunders.
I make and example how can achieve that with underscore template and handlebars. Use it for iterating over a collection of models to display a list of products.
Underscore.js
<tbody class="product-list">
<script type="text/template" id="product-template">
<% _.each(products.models, function(product){ %>
<tr>
<td><%= product.get('modelName') %></td>
<td><%= product.get('brand') %></td>
<td><%= product.get('year') %></td>
</tr>
<% }) %>
</script>
</tbody>
In script file define model:
var Product = Backbone.Model.extend({});
Next, define a collection and add those model to the collection:
var ProductList = Backbone.Collection.extend({
model: Product
});
Most of the time we use view in Backbone application to do the rendering:
var ProductView = Backbone.View.extend({
el: '.product-list',
template: _.template($('#product-template').html()),
render: function(products){
this.$el.html(this.template({
products: products
}));
}
});
You can see from working code full app, and see that we call render method from productView and pass it collection as argument: this.productView.render(this.collection)
Now we can use it as a list in template to iterate and display modelName, brand and year for each product in lists.
Working code: jsFiddle
I am particularly asked to use handlebars
Handlebars.js
You have many errors in your code:
define instance of view var products = new ProductView();, instead of that you define instance of ProductCollection();
var html=template(this.products.toJSON()); Cannot read property 'toJSON' of undefined , check initialize method in working example, you need to define collection and listen to him, because every time we add something to collection we want to render ProductView
el: '.table' not el: '.product-list',
var modelname= document.getElementById('modelname').value; var brandname ... - you make them as a global variables, instead of that place that variables inside create() method
replace var html=template(this.products.toJSON()); with $('.product-list').html(template(this.products.toJSON()))
First of all read documentation if something isn't clear: backbone.js and check working example: jsFiddle

based on current date- sort json data on button click

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);
}
});

Two way binding is not working with angular js

I have the html code like this:
<div ng-controller="MainCtrl">
<tr data-ng-repeat="element in awesomeThings">
<div ng-if="$even">
<td ng-click="getServiceDetails(element)">
<a href="#">
{{element['serviceDetail']['name']}}
</a>
</td>
</div>
</tr>
//after some html
<span >{{publicName}}</span>
</div>
My controller looks like this:
angular.module('dcWithAngularApp')
.controller('MainCtrl', function ($scope,$http,test) {
$scope.awesomeThings = {"serviceDetail":{"name":"batman"}}
$scope.getServiceDetails = function(serviceDetails)
{
console.log('Called')
$scope.publicName = serviceDetails.name
}
});
After clicking on the td tag, the span text are not changing! Even though me changing the publicName in the current scope!
Where I'm making the mistake?
You don't have a name property in your $scope.awesomeThings array.
Here I added some animals for you.
angular.module('dcWithAngularApp')
.controller('MainCtrl', function ($scope,$http,test) {
$scope.awesomeThings = [
{ name: "Dog" },
{ name: "Cat" }
];
$scope.getServiceDetails = function(serviceDetails)
{
console.log('Called')
$scope.publicName = serviceDetails.name
}
});
Edit:
I put together a JSFiddle that solves your edit.
http://jsfiddle.net/HB7LU/7191/
$scope.awesomeThings is an array of string so element does not have a 'name' property.
You also have a missing ; after your console.log which may be stopping the code from running.
It may help you to log what the object is.
<div ng-controller="MainCtrl">
<tr data-ng-repeat="element in awesomeThings">
<div ng-if="$even">
<td ng-click="getServiceDetails(element)">
<a href="#">
{{element.name}}
</a>
</td>
</div>
</tr>
//after some html
<span >{{publicName}}</span>
</div>
angular.module('dcWithAngularApp')
.controller('MainCtrl', function ($scope,$http,test) {
$scope.awesomeThings = {"serviceDetail":{"name":"batman"}};
$scope.getServiceDetails = function(serviceDetails)
{
console.log(serviceDetails);
$scope.publicName = serviceDetails.name;
}
});
Your main issue is this:
$scope.publicName = serviceDetails.name
It needs to be
$scope.publicName = serviceDetails;
$scope.awesomeThings is an array of strings, not objects. You're ng-repeating through the string array and passing the string to your getServiceDetails method, so 'serviceDetails' is just a string.
As an unrelated warning, I see you're using tr inside a div. The tr should be inside a table, thead, or tbody.

Resources