I am having a LayoutView in which I am having two regions named filter region and main region (Content Region). Based on the selection over filter region, I need to show the view into the main region.
As of now, I have created one view to show into the main region i.e Current Year view, but I need inputs on how to create a view for the other Wireframe that I am attaching into my question panel now.
// Application Bootstrap
var App = new Marionette.Application();
// Add a region
App.addRegions({
main: "#app"
});
/*DATA*/
var data = {
"accounts": [{
"accountNumber": "AllAccounts",
"assets": [{
"assetName": "ASSET 1",
"isin": "GB0008533564",
"grossProfit": [{
"assetCost": "500",
"units": "10",
"netGainLoss": "20"
}]
},
{
"assetName": "ASSET 2",
"isin": "GB0008533565",
"grossProfit": [{
"assetCost": "500",
"units": "10",
"netGainLoss": "20"
}]
},
{
"assetName": "ASSET 3",
"isin": "GB0008533566",
"grossProfit": [{
"assetCost": "500",
"units": "10",
"netGainLoss": "20"
}]
}
]
}]
};
// AssetsModel
var AssetsModel = Backbone.Model.extend({});
//AssetsCollection - will contain the assets array
var AssetsCollection = Backbone.Collection.extend({
model: AssetsModel,
getAssetCost: function() {
var assetCost = 0;
this.each(function(model) {
_(model.get('grossProfit')).each(function(gross) {
assetCost += parseInt(gross.assetCost, 10);
});
});
return assetCost;
},
getUnits: function() {
var units = 0;
this.each(function(model) {
_(model.get('grossProfit')).each(function(gross) {
units += parseInt(gross.units, 10);
});
});
return units;
},
getNetGainLoss: function() {
var netGainLoss = 0;
this.each(function(model) {
_(model.get('grossProfit')).each(function(gross) {
netGainLoss += parseInt(gross.netGainLoss, 10);
});
});
return netGainLoss;
}
});
// AccountsModel - unique idAttribute will be accountNumber and setting the assets key of AccountsModel to AssetsCollection
var AccountsModel = Backbone.Model.extend({
idAttribute: "accountNumber",
initialize: function(response) {
this.set('assets', new AssetsCollection(response.assets));
}
});
// AccountsCollection - will be containg the Acccounts Array
var AccountsCollection = Backbone.Collection.extend({
model: AccountsModel
});
// Passing the data.accounts to accountsCollection instance
var accountsCollection = new AccountsCollection(data.accounts);
// AppLayoutView - mainlayoutview of the application
var AppLayoutView = Marionette.LayoutView.extend({
template: Handlebars.compile($("#layout-view-template").html()),
regions: {
filter: "#filterArea",
main: "#contentArea" // mainContentArea regiobn- will be containing two type of views:
// 1. High level view, with multiple assets as table row's and only one object inside grossProfit
// 2. Deep level view, with multiple objects inside assets array as table and mutliple objects inside grossProfit array
// (second point, need to be discussed for which i am raising question)
},
onRender: function() {
this.showChildView("filter", new FilterView());
this.showChildView("main", new TableCompositeView({
collection: accountsCollection.get('AllAccounts').get('assets')
}));
}
});
var FilterView = Marionette.ItemView.extend({
id: "filter-view",
template: Handlebars.compile($('#filter-view-template').html())
});
var RowView = Marionette.ItemView.extend({
tagName: "tr",
template: Handlebars.compile($('#report-row-template').html())
});
var TableCompositeView = Marionette.CompositeView.extend({
id: "report-area-view",
tagName: "section",
template: Handlebars.compile($("#report-view-template").html()),
childView: RowView,
childViewContainer: "#childWrapper",
templateHelpers: function() {
var totalAssetCost = this.collection.getAssetCost();
var totalUnits = this.collection.getUnits();
var totalNetGainLoss = this.collection.getNetGainLoss();
return {
totalAssetCost: totalAssetCost,
totalUnits: totalUnits,
totalNetGainLoss: totalNetGainLoss
}
}
});
var layoutView = new AppLayoutView();
// Render the layoutView to the main Region
App.getRegion('main').show(layoutView);
App.start();
.container {
padding-top: 10px;
}
<div class="container">
<div class="row">
<div class="col-md-12">
<div id="app"></div>
</div>
</div>
</div>
<!--TEMPLATES -->
<script id="layout-view-template" type="text/handlebars-template">
<section>
<div id="filterArea"> </div>
<div id="contentArea"> </div>
</section>
</script>
<script id="filter-view-template" type="text/handlebars-template">
<div class="well">
<input type="radio" name="currentYear" value="currentYear" /> Current year <br/><br/>
<input type="radio" name="twoYears" value="pastYears" /> Past 2 year
</div>
</script>
<script id="report-view-template" type="text/handlebars-template">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Asset Name</th>
<th>Asset Cost</th>
<th>Units</th>
<th>NetGainLoss</th>
</tr>
</thead>
<tbody id="childWrapper"></tbody>
<tfoot>
<tr>
<th>Total</th>
<th>₹ {{totalAssetCost}}</th>
<th>₹ {{totalUnits}}</th>
<th>₹ {{totalNetGainLoss}}</th>
</tr>
</tfoot>
</table>
</script>
<script id="report-row-template" type="text/handlebars-template">
<td>{{assetName}}</td>
{{#grossProfit}}
<td>{{assetCost}}</td>
<td>{{units}}</td>
<td>{{netGainLoss}}</td>
{{/grossProfit}}
</script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.marionette/2.4.2/backbone.marionette.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.0/handlebars.min.js"></script>
Please use the below data to show the Past 2 Years view, there is only minor changes i.e only the grossProfit array objects have been increased.
var data = {
"accounts": [{
"accountNumber": "AllAccounts",
"assets": [{
"assetName": "ASSET 1",
"isin": "GB0008533564",
"grossProfit": [{
"assetCost": "500",
"units": "10",
"netGainLoss": "20"
},
{
"assetCost": "500",
"units": "10",
"netGainLoss": "20"
}
]
},
{
"assetName": "ASSET 2",
"isin": "GB0008533565",
"grossProfit": [{
"assetCost": "500",
"units": "10",
"netGainLoss": "20"
},
{
"assetCost": "500",
"units": "10",
"netGainLoss": "20"
}
]
},
{
"assetName": "ASSET 3",
"isin": "GB0008533566",
"grossProfit": [{
"assetCost": "500",
"units": "10",
"netGainLoss": "20"
},
{
"assetCost": "1000",
"units": "10",
"netGainLoss": "20"
}
]
}
]
}]
};
Case 1:If you have to show completely different composite view within the main region,you have to create a separate layout 'ResultLayout' which should be rendered in Main Region.You can intialized both the compositeview's in ResultLayout and render the desired compositeview when the filter is changed.(This is the case when your data is static for different filters)
In case of dynamic data
Case 2: If you have to show completely different composite view within the main region, you have to create a separate layout 'ResultLayout' which should be rendered in Main Region.You can render the desired compositeview when the filter is changed.
For first time you can show default filter selected and corresponding compositeview is render within the layout(ResultLayout) of main region.
On filter change you can trigger event from FilterView which will be listened in ResultLayout (with filter params), fetch the collection according to the filters and then you can render the corresponding compositeview in the region of 'ResultLayout' The hierarchy will be as below:
LayoutView -> Filter Region and Main Region
Main Region -> ResultLayout
ResultLayout -> CompositeView1 or CompositeView2 (Depending upon the filters.)
Case 3: If you have to keep compositeview same then you just need to update the collection and render the view.
I hope this helps!
Related
I am facing issue to store category SINGLES related data into an array and then use this array to display show data.Basically, I just want to store data that is only belong to category "SINGLES" from json file that I named it "data.json" into an array.Can anyone help me please. I would really appreciate that.
Index.html
<div id="app">
<div class="col-lg-4 col-sm-6" v-for="model in jsonSingleData">
<div class="beeton-models-box">
<div class="image-holder">
</div>
<div class="text-box">
<h3>{{model.title}}</h3>
<p>{{model.bedrooms}}</p>
</div>
</div>
</div>
</div>
script.js
var vm = new Vue({
el:'#app',
data:{
jsonSingleData:[]
},
created:function(){
this.fetchDataAll();
},
methods:{
fetchDataAll: function(){
var url="data.json";
axios.get(url)
.then(function(res){
res.data.models.forEach(single=>{
if(single.category=='SINGLES')
{
vm.jsonSingleData=single;
console.log(single);
}
});
});
}
The below is my json file.
data.json
{
"models": [
{
"title": "IRIS",
"project": "ABC",
"category": "SINGLES",
"bedrooms": 3
},
{
"title": "LILAC",
"project": "ABC",
"category": "DOUBLE",
"bedrooms": 4
},
{
"title": "ASTER",
"project": "ABC",
"category": "SINGLES",
"bedrooms": 4
}
]
}
Looks like your method is missing some points. Also, you are missing a } at the end.
Try this:
fetchDataAll: function(){
var vm = this;
var url="data.json";
axios.get(url)
.then(function(res){
res.data.models.forEach((single)=>{
if(single.category=='SINGLES')
{
vm.jsonSingleData.push(single);
console.log(single);
}
});
});
}
I am working with multiple angularjs data tables and generating a new table every time user selects an option from the drop down list.Based on the user's selection i make an $http request to fetch new data from the database .For every table i have different dtColumnDefs which is set dynamically since my table column headers are dynamic except 1st two and last columns.My intention is to disable sorting for these dynamic column headers.I am able to find out total number of dynamic columns then run a loop to dynamically disable sorting on those columns.Though the data table renders successfully for every user input but expected columns sorting options are not getting disabled.
Check the plunker for demo.
UPDATE
This is a demo table to understand how to proceed but my original table is little bit complex where i am showing some database rows as column headers and there is also some filtering such as unique ,i am also using index value to count the serial so i could not accept davidkonrad's answer as i don't want to define columns from controller.
var app = angular.module('myApp', ['datatables']);
app.controller('MyCtrl', function($scope, DTOptionsBuilder, DTColumnBuilder, DTColumnDefBuilder) {
$scope.department = [{
value: "1",
name: "sales"
},
{
value: "2",
name: "admin"
},
{
value: "3",
name: "other"
}
];
$scope.dep = $scope.selected_dep;
$scope.i = 0;
$scope.depshow = function() {
$scope.i += 1;
var x = 'v' + $scope.i;
$scope.m = 'v' + $scope.i;
$scope.dep = $scope.selected_dep;
if ($scope.dep == 1) {
$scope.list = [{
"eid": "10",
"dyn1": "dval1",
"dyn2": "dval2",
"dyn3": "dval3",
"sales": "20"
},
{
"eid": "20",
"dyn1": "dval1",
"dyn2": "dval2",
"dyn3": "dval3",
"sales": "20"
},
{
"eid": "30",
"dyn1": "dval1",
"dyn2": "dval2",
"dyn3": "dval3",
"sales": "20"
}
];
} else if ($scope.dep == 2) {
$scope.list = [{
"eid": "40",
"dyn1": "dval1",
"dyn2": "dval2",
"dyn3": "dval3",
"sales": "20"
},
{
"eid": "50",
"dyn1": "dval1",
"dyn2": "dval2",
"dyn3": "dval3",
"sales": "20"
},
{
"eid": "60",
"dyn1": "dval1",
"dyn2": "dval2",
"dyn3": "dval3",
"sales": "20"
}
];
}
if ($scope.dep == 3) {
$scope.list = [{
"eid": "70",
"dyn1": "dval1",
"dyn2": "dval2",
"dyn3": "dval3",
"sales": "20"
},
{
"eid": "80",
"dyn1": "dval1",
"dyn2": "dval2",
"dyn3": "dval3",
"sales": "20"
},
{
"eid": "0",
"dyn1": "dval1",
"dyn2": "dval2",
"dyn3": "dval3",
"sales": "20"
}
];
}
$scope.x = {};
$scope.x.dtOptions = DTOptionsBuilder.newOptions()
.withOption('order', [0, 'asc']);
$scope.ln = 4;
$scope.x.dtColumnDefs = [];
for (var i = 1; i < $scope.ln; i++) {
$scope.x.dtColumnDefs.push(DTColumnDefBuilder.newColumnDef(i).notSortable());
}
}
});
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script src="http://phpflow.com/demo/angular_datatable_demo/angular-datatables.min.js"></script>
<script src="http://phpflow.com/demo/angular_datatable_demo/jquery.dataTables.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<link rel="stylesheet" href="http://phpflow.com/demo/angular_datatable_demo/datatables.bootstrap.css">
</head>
<div class="container">
<div ng-app="myApp" ng-controller="MyCtrl">
Select <select ng-model="selected_dep" ng-change="depshow()" ng-options="item.value as item.name for item in department">
<option value="">select a department</option>
</select>
<table class="table table-striped table-bordered" datatable="ng" dt-options="m.dtOptions" dt-column-defs="m.dtColumnDefs" >
<thead>
<tr>
<th>sr</th>
<th>Employee ID</th>
<th>dynamic clm1</th>
<th>dynamic clm2</th>
<th>dynamic clm3</th>
<th>sales</th>
</thead>
<tbody>
<tr ng-repeat="data in list">
<td> {{$index+1}} </td>
<td> {{ data.eid }} </td>
<td> {{ data.dyn1 }} </td>
<td> {{ data.dyn2 }} </td>
<td> {{ data.dyn3 }} </td>
<td> {{ data.sales }} </td>
</tr>
</tbody>
</table>
</div>
</div>
OK. Dont know where to start, but you a had broad range of errors in your code (no offense).
Never declared x
Never actually used x
Never actually used dtColumnDefs
And more...After some debugging the overall setup did work. However, your biggest problem was the mix of ng-repeat combined with the datatable directive combined with redeclaring the same properties over and over. It was easy to fix the code, but not easy to overcome this extreme race condition. Spent an hour trying to work it out, but it is not possible without a lot of $compile's, $apply's and $timeout's.
It really do not have to be so complicated. As I understand you had two issues 1) notSortable did not work 2) you could have different columns (properties) for different lists. Simply let dataTables render the data, and declare dtColumns dynamically each time a new list is selected :
var columns = [];
for (var prop in $scope.list[0] ) {
columns.push({ data: prop })
}
$scope.x.dtColumns = columns;
Set $scope.list as data source :
$scope.x.dtOptions = DTOptionsBuilder.newOptions()
.withOption('data', $scope.list)
render the "dataTables way" :
<table datatable="" ....></table>
forked plnkr -> http://plnkr.co/edit/afqKW5uKW7Skfnm62zfq?p=preview
Try using square brackets inside the dtColumnDefspush like
$scope.x.dtColumnDefs.push(DTColumnDefBuilder.newColumnDef([i]).notSortable());
I have an object and within this object I have items and one of the items is an array which also contains objects. A sample of the data is shown below.
I am using knockout to bind this data to the view so I think I need to implement a double loop for returning the objects and the objects within the child array to be able to bind them in the view.
Sample data:
"singers": {
"ijiyt6ih": {
"id": ObjectId('ijiyt6ih'),
"name": "John",
"songs": [
{
"id": ObjectId('okoiu8yi'),
"songName": "Hello There",
"year": "1980"
},
{
"id": ObjectId('sewfd323'),
"songName": "No More",
"year": "1983"
}
]
},
"98usd96w": {
"id": ObjectId('98usd96w'),
"name": "Jack",
"songs": [
{
"id": ObjectId('iew342o3'),
"songName": "Hurry Up",
"year": "1985"
}
]
}
}
I need to find a way to appropriately loop through this so that I can modify the returned data to bind it to the viewModel using knockout.
Here is how my viewModel looks like:
singersViewModel = function(data) {
var self = {
singerId: ko.observable(data.id),
singerName: ko.observable(data.name),
songName: ko.observable(...),
songYear: ko.observable(...)
};
I am not sure if I will have to return two different sets of data or not.
As for the looping. I was able to loop and return the list of singers to display on the page but I am not able to get the list of songs displayed within each singer.
Here is my loop so far:
var self = {},
singer,
tempSingers = [];
self.singers = ko.observableArray([]);
for (singer in singers) {
if (singers.hasOwnProperty(singer)) {
tempSingers.push(new singersViewModel(singers[singer]));
}
}
self.singers(tempSingers);
I tried to duplicate the same type of loop for songs within this loop but i would get an error using hasOwnProperty because songs is an array.
In the included snippet you can see how you can map the original data to a viewmodel that can be bound to a view.
I've left the ids as regular properties, and converted the names into observables, so thatthey can be edited. At the bottom you can see the current viewmodel state.
There is also a sample view which iterates the list of singers, and also the list of song within each singer.
As you can see I'm implementing the solution using mapping. For mapping you need to implement a callback that receives each original object and returns a new one with a new structure. For example this part of the code
_.map(_singers, function(singer) {
return {
id: singer.id,
name: ko.observable(singer.name),
// ... songs:
})
iterates over each singer (the sample data in the question), and for each one creates a new object with the id, an observable which includes the name (and the mapping of songs, which I don't show in this fragment).
NOTE: I'm using lodash, but many browsers support map natively as an array function
var ObjectId = function (id) { return id; }
var singers = {
"ijiyt6ih": {
"id": ObjectId('ijiyt6ih'),
"name": "John",
"songs": [
{
"id": ObjectId('okoiu8yi'),
"songName": "Hello There",
"year": "1980"
},
{
"id": ObjectId('sewfd323'),
"songName": "No More",
"year": "1983"
}
]
},
"98usd96w": {
"id": ObjectId('98usd96w'),
"name": "Jack",
"songs": [
{
"id": ObjectId('iew342o3'),
"songName": "Hurry Up",
"year": "1985"
}
]
}
};
var SingersVm = function(_singers) {
var self = this;
self.singers = _.map(_singers, function(singer) {
return {
id: singer.id,
name: ko.observable(singer.name),
songs: _.map(singer.songs, function(song) {
return {
name: ko.observable(song.songName),
id: song.id
};
})
};
});
return self;
};
var vm = new SingersVm(singers);
//console.log(vm);
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-bind="foreach: singers">
<div>
<input data-bind="value: name"/> (<span data-bind="text: id"></span>)
<ul data-bind="foreach:songs">
<li>
<input data-bind="value: name"/> (<span data-bind="text: id"></span>)
</li>
</ul>
</div>
</div>
<pre data-bind="html: ko.toJSON($root,null,2)">
</pre>
I have been following the Angular tutorials, and I am trying to get my JSON data to appear, yet I know I am doing something wrong, but can't figure out the proper method.
I know that somewhere in my app.js my scope is messed up.
How can I display the Family Name of each product?
Here is the layout I have:
app.js
var eloApp = angular.module('eloMicrosite', []);
eloApp.controller('homeListController', ['$scope', '$http',
function($scope, $http) {
$http.get('/Elo/eloMS.min.json')
.success(function(data) {
$scope.products = data;
});
}]);
eloApp.controller('HomeController', function(){
this.products = $scope.products;
});
HTML
<div ng-controller="HomeController as home">
{{home.products[o]["Family Name"]}}
</div>
JSON Layout
{
"products": [
{
"Family Name": "3201L",
"Type": "IDS",
"Size (inches)": 32,
"Aspect Ratio": "16:9",
"Part Number": "E415988",
"Product Description": "ET3201L-8UWA-0-MT-GY-G",
"Marketing Description": "3201L 32-inch wide LCD Monitor",
"Advance Unit Replacement": "",
"Elo Elite": "",
"Package Quantity": 1,
"Minimum Order Quantity": 1,
"List Price": 1800
},
.
.
.
],
"families": [
{
category: "Category1"
},
{
category: "Category2"
}
],
"accessories": [
{
category: "Category1"
},
{
category: "Category2"
}
]
}
You should add homeListController on your page instead of HomeController, Also need to use this instead of using $scope as you wanted to follow controllerAs syntax, 2nd controller is useless in this scenario, you could remove that from app.js.
Markup
<div ng-controller="homeListController as home">
{{home.products[0]["Family Name"]}}
</div>
Controller
eloApp.controller('homeListController', ['$http',
function($http) {
var home = this;
$http.get('/Elo/eloMS.min.json')
.success(function(data) {
home.products = data.products; //products should mapped here
});
}]);
Demo Plunkr
I'm trying to render a list with a Marionette CompositeView. I am not sure why the rendered list just has an item displaying the word result. I was expecting the first item to display Level 1.
Here is a fiddle to my current code: http://jsfiddle.net/16L1hen4/
Here is my JS, template, and data:
JavaScript:
var App = new Backbone.Marionette.Application();
App.addRegions({
mainRegion: '#main'
});
var TreeModel = Backbone.Model.extend({
});
var TreeCollection = Backbone.Collection.extend({
model: TreeModel,
url: 'https://api.mongolab.com/api/1/databases/backbone-tree/collections/tree?apiKey=somekey'
});
var TreeView = Backbone.Marionette.CompositeView.extend({
initialize: function() {
console.log(this.collection);
},
tagName: 'ul',
template: _.template( $('#tree-template').html() )
});
var treeCollection = new TreeCollection();
treeCollection.fetch().done(function () {
var treeView = new TreeView({collection: treeCollection});
App.mainRegion.show(treeView);
});
Template:
<div id="main"></div>
<script type="text/template" id="tree-template">
<li><%- name %></li>
</script>
JSON Data:
{
"_id": {
"$oid": "54adab80e4b0aa674b256836"
},
"name": "Level 1",
"children": [
{
"name": "Child 1 - Level 2",
"children": [
{
"name": "Jon - Level 3"
},
{
"name": "Mary - Level 3"
}
]
},
{
"name": "Child 2 - Level 2",
"children": [
{
"name": "Bill - Level 3"
}
]
}
]
}
Read the marrionnete docs a bit closer - you need a childView defined....
You are using a CompositeView to display a Collection, but you need to define a childView to render the models
var LeafView = Backbone.Marionette.ItemView.extend({
// ...
});
var TreeView = Backbone.Marionette.CollectionView.extend({
childView: LeafView
})
here is an updated fiddle. http://jsfiddle.net/6ok1rptq/
Now the "result" showing in the html, without being familiar with the underscore source, I believe this is caused by the fact that the data given to the template is null, and a quick look at the source of underscore shows that it is using with
http://underscorejs.org/docs/underscore.html#section-148
"If a variable is not specified, place data values in local scope."
Meaning that the template can't find a "name" variable, and will instead look it up in the global scope (window)
Result is just the name of the jsfiddle iframe containing the result of the fiddle
<iframe name="result" ...>
I didn't test this, but I assume that the error lies with the fact that you didn't define a Marionette Itemview on the CompositeView.
The logical structure is to pass the Compositeview a collection as you did in the question, and the models will be rendered in separate itemviews.
In the itemview you can call:
this.model.get("property");
To access the properties from within the view.