AngularJS dynamic routing from index to detailed page - javascript

I'm trying to route from an index list of items to a page that will display a detailed view of that item.
In my index view I have a table that iterates through all the items that are saved in the database.
There is a button under the actions column that will take me to events/show route using ng-click="go('events/show')"
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Title</th>
<th class="col-md-2">Actions</th>
</tr>
</thead>
<tbody>
<tr scope="row" ng-repeat="event in events | reverse | filter:filterByUID">
<td>{{event.title}}</td>
<td class="col-md-2">
<div class="btn-group" role="group" aria-label="actions">
<button class="btn btn-primary" ng-click="go('events/show')">
<span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span>
</button>
<button class="btn btn-primary" ng-click="events.$remove(event)">
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
</button>
</div>
</td>
</tr>
</tbody>
</table>
The table looks like this:
In my controller I have:
$scope.go = function ( path ) {
$location.path( path );
};
in my routes.js I have:
.whenAuthenticated('/events/show', {
templateUrl: 'views/eventShow.html',
controller: 'eventShowCtrl'
})
Everything works so far.
However, what is unclear to me is how do I pass the event id to the eventShow.html page, so I know which item was clicked from the index list, so I can display the detailed information?
My firebase database looks like this:

Check out ui-router, it makes dynamic routing much easier
https://github.com/angular-ui/ui-router
But if you want to keep what you have, you should pass the event id into your path, like such
$scope.go = function ( path, event ) {
$location.path( path + "/" + event.id );
};
.whenAuthenticated('/events/show/:eventId', {
templateUrl: 'views/eventShow.html',
controller: 'eventShowCtrl'
})
and in your controller, access $stateParams.eventId to load that event.

You should use a variable in your router:
.whenAuthenticated('/events/:id', {
templateUrl: 'views/eventShow.html',
controller: 'eventShowCtrl'
})
Then you can simply use the ID in your function call:
go('events/:id')
Here's a great tutorial (and I highly recommend watching all of both parts).
And you'll have nicer URLs that can be bookmarked.

One you could pass the UID(uid is just an example for user id) onClick
<tr scope="row" ng-repeat="event in events | reverse | filter:filterByUID">
<td>{{event.title}}</td>
<td class="col-md-2">
<div class="btn-group" role="group" aria-label="actions">
<button class="btn btn-primary" ng-click="go('events/show', event.UID)">
<span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span>
</button>
<button class="btn btn-primary" ng-click="events.$remove(event)">
<span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
</button>
</div>
</td>
</tr>
Then in your js file
$scope.go = function ( path, uid ) {
$location.path( path + "/" + uid );
};
.whenAuthenticated('/events/show/:eventId', {
templateUrl: 'views/eventShow.html',
controller: 'eventShowCtrl'
})
Then to query firebase, say you have a field in your objects called uid, you can use startAT and endAT methods.
See here for example
And here to read more on filtering

Related

Accessing dynamically created variable in onclick

I have a foreach loop, enumerating my models to create a table. In this table, i need to have an edit button for each model where i call a javascript function to show a modal.
I need to pass the model into the javascript function, but i can't get this to work. I've worked out how to dynamically create the variables, but not how to use it as input.
Right now, it's just hardcoded to use 'department1', which is just the first created. I need toggleManageDepartmentModal to be called with (department + #department.Id)
Creating the table
#foreach (var department in Model.PaginatedDepartments())
{
<tr>
<td>#department.Name</td>
<td>#department.Description</td>
<td class="min">#department.Created.ToLocalTime().ToString("dd-MM-yyyy")</td>
<td class="min">
<div class="text-nowrap">
<script>
//Dynamically create variables for each department
eval('var department' + #department.Id + '= #Json.Serialize(department);');
</script>
<button type="button" class="btn btn-secondary btn-sm" onclick="toggleManageDepartmentModal(department1)">
<span class="fa-solid fa-pen-to-square" aria-hidden="true"></span>
Rediger
</button>
</div>
</td>
</tr>
}
Javascript function to show modal
function toggleManageDepartmentModal(department) {
var model = {
department : department,
controller : 'Admin',
action : 'ManageDepartment'
};
$.ajax({
type: "Post",
url: "/Modals/ShowManageDepartmentModal",
data:model,
success: function (data) {
$("#loadModal").html(data);
$('#modal-manage-department').modal('show')
}
})
}
I would like to do something like this:
<button type="button" class="btn btn-secondary btn-sm" onclick='toggleManageDepartmentModal(Eval("department" + #department.Id))'>
<span class="fa-solid fa-pen-to-square" aria-hidden="true"></span>
Rediger
</button>
I am not exactly familiar with the tool (a templating engine?) you are using to build your HTML, but I will try to help.
Traditionally, before the JS framework takeover, the way to attach data to HTML elements was to use data-attributes. In your case, I would use something like data-department. I would dare to say that it's much better way then using script tags + eval()
The simplest way would be to attach the data to the button. Probably like a serialized JSON:
<button data-department="#DataGoesHere" type="button" class="btn btn-secondary btn-sm">
Rediger</button>
How about the onclick function? You can get the button's reference by using this argument:
<button onclick="toggleManageDepartmentModal(this)" data-department="#DataGoesHere" type="button" class="btn btn-secondary btn-sm">
Rediger</button>
Then, you can access the data by querying this.dataset.department:
function toggleManageDepartmentModal(targetElement) {
// `this` is event's target element
const department = targetElement.dataset.department;
// or rather JSON.parse(targetElement.dataset.department)
// or targetElm.getAttribute('data-department')
…
}
There's one caveat – because data-attributes are part of the 'public' markup, you really should not put anything confidential in there (but I guess that this is not the case).
I ended up taking a little different approch which works very well.
#foreach (var department in Model.PaginatedDepartments())
{
<tr>
<td>#department.Name</td>
<td>#department.Description</td>
<td class="min">#department.Created.ToLocalTime().ToString("dd-MM-yyyy")</td>
<td class="min">
<div class="text-nowrap">
<script>
//Store model JSON in localStorage
localStorage.setItem('department' + #department.Id, JSON.stringify(#Json.Serialize(department)))
</script>
<button type="button" class="btn btn-secondary btn-sm" onclick="toggleManageDepartmentModal(#department.Id)">
<span class="fa-solid fa-pen-to-square" aria-hidden="true"></span>
Rediger
</button>
</div>
</td>
</tr>
}
function toggleManageDepartmentModal(id) {
var modelJSON = localStorage.getItem('department' + id);
var model = {
department : JSON.parse(modelJSON),
controller : 'Admin',
action : 'ManageDepartment'
};
$.ajax({
type: "Post",
url: "/Modals/ShowManageDepartmentModal",
data:model,
success: function (data) {
$("#loadModal").html(data);
$('#modal-manage-department').modal('show')
}
})
}

unwanted angular value link

The picture shows an edit page, which use can add commands to the list, delete and so on. The value should be only updated to the actual array when user click update button. Below are some of my code:
$scope.editSchedule = function(index){
console.log(index);
$scope.editScheduleValue = {
name: $scope.currentSchedule[index].name,
trigger: $scope.currentSchedule[index].trigger,
repeat: $scope.currentSchedule[index].repeat,
commandList: $scope.currentSchedule[index].commandList,
scheduleIndex: index
};
var dailog = $uibModal.open({
templateUrl: 'app/partials/edit-schedule.html',
controller: editScheduleController,
size: 'lg',
scope: $scope
});
};
This is a edit button scope, which will get the actual value from curremtSchedule array.
$scope.addCommand = function(){
console.log("addCommand");
$scope.addRoom = $scope.equipment[$scope.roomSelected].name;
$scope.addEquipment = $scope.equipment[$scope.roomSelected].equipment[$scope.equipmentSelected].name;
$scope.addEquipmentCommand = $scope.equipment[$scope.roomSelected].equipment[$scope.equipmentSelected].command[$scope.commandSelected].type;
$scope.editScheduleValue.commandList.push({
room: $scope.addRoom,
equipment: $scope.addEquipment,
command: $scope.addEquipmentCommand
})
};
This is my Add command button code, which push data to editScheduleValue array.
HTML:
<tr ng-repeat="x in editScheduleValue.commandList" ui-tree-node>
<td style="width: 5%"><i class="glyphicon glyphicon-resize-vertical" ui-tree-handle></i> </td>
<td style="width: 5%">{{$index+1}}</td>
<td style="width: 30%">{{x.room}}</td>
<td style="width: 30%">{{x.equipment}}</td>
<td style="width: 30%">{{x.command}}</td>
<td>
<a class="pull-right btn btn-danger btn-xs" data-nodrag ng-click="remove(this)">
<span class="glyphicon glyphicon-remove"></span>
</a>
</td>
</tr>
The problem that I encouter is whenever I delete, add command not only the editScheduleValue array updated, but the currentSchedule array as well, I really do not understand why is this 2 array is somehow linked. Please help~~~
Thank you.
I replace
commandList: $scope.currentSchedule[index].commandList,
With
commandList: angular.copy($scope.currentSchedule[index].commandList),
and this 2 arrays are not link anymore, I do not quite understand why it is, but here the answer for my problem.

How to access current row data in angular-datatables using templates?

I am using angular-datatables. There is a column Actions which I render using an inline template. I want to access current row data in that template. How do that?
controller
$scope.dtOptions = DTOptionsBuilder.newOptions().withOption('ajax', {
url: '/api/department',
type: 'GET'
})
.withDataProp('data')
.withOption('processing', true)
.withOption('serverSide', true)
.withPaginationType('full_numbers')
.withOption('createdRow', function (row, data, dataIndex) {
return $timeout(function() {
// Recompiling so we can bind Angular directive to the DT
return $scope.$apply($compile(angular.element(row).contents())($scope));
});
})
.withBootstrap();
$scope.dtColumns = [
DTColumnBuilder.newColumn('id').withTitle('ID'),
DTColumnBuilder.newColumn('name').withTitle('Name'),
DTColumnBuilder.newColumn('actions').withTitle('Actions').withOption("searchable", false)
];
view
<div class="hbox hbox-auto-xs hbox-auto-sm" ng-controller="DepartmentsController">
<!-- Inline Template -->
<script type="text/ng-template" id="actions.html">
<button class="btn btn-primary btn-xs"
ng-click="edit(/** CURRENT ROW ELEMENT ID */)"><i class="fa fa-edit"></i> Edit</button>
<button class="btn btn-danger btn-xs"
ng-click="delete()"><i class="fa fa-trash"></i> Delete</button>
</script>
<div class="bg-light lter b-b wrapper-md">
<h1 class="m-n font-thin h3">Departments</h1>
</div>
<div class="wrapper-md">
<div class="panel panel-default">
<div class="panel-body">
<div class="row">
<div class="col-xs-6">
<button class="btn m-b-md btn-md btn-primary " ui-sref="manager.departments.create">
<i class="fa fa-plus"></i> <span class="hidden-sm hidden-xs">Add Department</span></button>
</div>
</div>
<div class="row">
<div class="col-sm-12 m-b-xs">
<table datatable="" dt-options="dtOptions" dt-columns="dtColumns" class="table table-striped b-t b-b">
<thead>
<tr>
<th style="width:20%">ID</th>
<th style="width:60%">Name</th>
<th style="width:20%">Actions</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
Here is plunkr to help you: http://plnkr.co/edit/iAZBof7g6cp68RnM0X8H?p=preview
After hours of struggle, I found the solution. It's quite obvious when you see it.
I created a new scope and added data to it before passing it to $compile in createRow callback. Creating a new scope is necessary to pass unique data to each row. If you simply passed by $scope.row then each row will have the same row equal to the last row processed.
controller
.withOption('createdRow', function (row, data, dataIndex) {
// Create a new scope for each row, otherwise, data will
// not be unique for each row becuase of data bindings
var $newScope = $scope.$new(true);
$newScope.row = data;
// Pass any methods you are using in current scope
$newScope.delete = $scope.delete;
return $timeout(function() {
// Recompiling so we can bind Angular directive to the DT
return $scope.$apply($compile(angular.element(row).contents())($newScope));
});
});
view
<script type="text/ng-template" id="actions.html">
<button class="btn btn-primary btn-xs" ui-sref="manager.departments.edit({id: {{ row.id }} } )"><i class="fa fa-edit"></i> Edit</button>
<button class="btn btn-danger btn-xs" ng-bootbox-confirm="Are you sure you want to delete this department?" ng-bootbox-confirm-action="delete(row.id)"><i class="fa fa-trash"></i> Delete</button>
</script>
I used the above accepted answer, and it worked fine. However, later when we moved to production and the rows per page changed from 20 to 500, I saw significant performance issues through chrome developer tools (Most time spent on hundreds of setTimer and listener events)
I found the official document here which gives us an example as below:
.withOption('createdRow', createdRow);
// ...
function createdRow(row, data, dataIndex) {
// Recompiling so we can bind Angular directive to the DT
$compile(angular.element(row).contents())($scope);
}
This piece of code does not use the $timeout or $apply functions, but still works well. If you run into performance issues as I did, this may help.

How to reload angularJs ng-table

I have an ng-table. I have multiple ng-tables inside one controller. I am giving dynamic attributes i.e. ng-table="tableParams2" or ng-table="tableParams3" etc. to them.
I am making an ajax request on button click function to update the data. My http request is being sent at backend. By after I click 3-4 times, I see in console my table is reloaded. By after data, my data remains constant, I don't see the reloaded content in table. Below is my code:
Html:
<button ng-click="qualifyX(2)" ></button>
<div class="dragable modal hide fade ui-draggable in" id="ptn_popup" aria-hidden="false" data-backdrop="false">
<div class="modal-header">
<a class="close" data-dismiss="modal" data-original-title="" title="">×</a>
<h4>Possible matched Companies</h4>
</div>
<div class="modal-body" style="padding: 10px;">
<div id="ptn_qualify_res" class="grid-view">
<div class="summary"></div>
<table ng-table="tableParams2" show-filter="true" class="items table table-striped table-bordered table-condensed">
<tr ng-repeat="business in $data">
<td data-title="'Primary Trading Name'" sortable="'primary_trading_name'" filter="{ 'primary_trading_name': 'text' }">
{{business.primary_trading_name}}
</td>
<td data-title="'Primary Entity Name'" sortable="'primary_entity_name'" filter="{ 'primary_entity_name': 'text' }">
{{business.primary_entity_name}}
</td>
<td data-title="'Business Name(s)'" sortable="'business_names'" filter="{ 'business_names': 'text' }">
{{business.business_names}}
</td>
<td data-title="'Other Trading Name(s)'" sortable="'other_trading_names'" filter="{ 'other_trading_names': 'text' }">
{{business.other_trading_names}}
</td>
<td data-title="'State'" sortable="'state'" filter="{ 'state': 'text' }">
{{business.state}}
</td>
<td style="width:70px;">
<a data-dismiss="modal" href="javascript:void(0)" data={{business.business_id}} class="ptn_qualify_view_link">
<button type="button" class="btn btn-mini"><i class="icon-eye-open"></i> View </button>
</a>
</td>
</tr>
</table>
</div>
</div>
<div class="modal-footer">
<a data-dismiss="modal" class="btn" id="yw11" href="javascript:void(0);" data-original-title="" title="">Close</a>
</div>
</div>
App.js
$scope.qualifyX = function(busID) {
var penModal = $('#popups_container' + busID + ' #pen_popup');
var pen = $('#popups_container' + busID).next().find('input#Custombusiness_primary_entity_name').val();
var selectors = {pen: pen, penModal: penModal};
$http.get(getPtnData + '?ptn=' + selectors.ptn).success(function(data) {
selectors.ptnModal.find('#ptn_qualify_res').removeClass('grid-view-loading').addClass('grid-view');
$scope['tableParams' + busID] = new ngTableParams(
{
page: 1, // show first page
count: data.length, // count per page
sorting:
{
primary_trading_name: 'asc' // initial sorting
}
}, {
total: 0, // length of data
getData: function($defer, params) {
var filteredData = params.filter() ?
$filter('filter')(data, params.filter()) :
data;
var orderedData = params.sorting() ?
$filter('orderBy')(filteredData, params.orderBy()) :
data;
params.total(orderedData.length); // set total for recalc pagination
$defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}
});
});
};
Create a somewhat similar Plunker, on every click I want to reload the table with new data.
I was having a very similar problem where my table was rendering but not reloading upon an action. What you need to do is to reload $scope.tableParams every time your button is clicked. A simple way to do this is to wrap $scope.tableParams.reload() in a function, and then call that function when the button is clicked.
controller code:
$scope.doSearch = function () {
$scope.tableParams.reload();
}
html code:
<button ng-click="doSearch()">Search</button>
I resolved finally the problem.
When I received the update data for the table it's necessary reload the table as follows:
$scope.tableData = data;
$scope.tableParams.total($scope.tableData.length);
$scope.tableParams.reload();
in case anyone else hits this. I created my own filter that creates a new size array.
I used
$scope.tableParams.total(data.length)
to update the length before reloading the table.
This code works for me ,
write it in your function- where you get your dynamic data
$scope.tableParams.reload();
$scope.tableParams.page(1);
$scope.tableParams.sorting({});

EmberJS re-use same template, but displays the template twice

I am playing with Ember, and building a basic contact management app to learn Ember. I am following the Emberjs getting started guide. Only instead of doing a "to-do" app, Im doing my own thing in hopes of picking it up better.
My Router, and Routes:
App.Router.map(function() {
this.resource('users', function() {
this.resource('user', { path: ':user_id' });
this.route('motoDigitalTrue');
});
this.resource('about');
});
App.UsersRoute = Ember.Route.extend({
model: function() {
return App.User.find();
}
});
App.UsersMotoDigitalTrueRoute = Ember.Route.extend({
model: function(){
return App.User.filter(function(user) {
if (user.get('motoDigital')) {
return true;
}
});
},
renderTemplate: function(controller) {
this.render('users', {
controller:controller
});
}
});
Essentially, I have a template named 'users' that I want to reuse. This template lists all the users. I have a sorting button that when clicked, will only display the users who have the motoDigitalTrue property set to true. The sorting is correct, but it just displays another Users template, rather than re-populating the original.
My Users template:
<script type="text/x-handlebars" id="users">
<div class="span10 tableContainer">
<button class="btn btn-primary createUser" {{action createUser}}><i class="icon-plus icon-white"></i> Add a Contact</button>
<div class="btn-group">
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">Sort<span class="caret"></span></a>
<ul class="dropdown-menu">
{{#linkTo 'users.motoDigitalTrue' activeClass="selected"}}Receiving MOTO Digital{{/linkTo}}
</ul>
</div>
<div class="tableScrollable">
<table class="table table-striped">
<thead>
<tr>
<th class="nameHead">Name</th>
<th class="companyHead">Company</th>
<th class="emailHead">Email</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name">&nbsp</td>
<td class="company">&nbsp</td>
<td class="email">&nbsp</td>
</tr>
{{#each model}}
<tr>
<td class="name"><i class="icon-user"></i> <strong>{{#linkTo 'user' this }}{{firstName}} {{lastName}}{{/linkTo}}</strong></td>
<td class="company">{{company}}</td>
<td class="email"><i class="icon-envelope"></i> <a {{bindAttr mailto="email"}}>{{email}}</a></td>
</tr>
{{/each}}
</tbody>
</table>
</div>
</div>
<div class="span3">
{{#if isCreateUser}}
<div class="well">
{{partial 'users/createUser'}}
<button {{action 'saveUser'}} class="btn btn-primary"><i class="icon-ok icon-white"></i> Save</button>
</div>
{{else}}
{{outlet}}
{{/if}}
</div>
</script>
I have been unable to find an answer, and any help would be appreciated!
I guess in your case to reuse templates, you should try using a partial, have a look here.
For example, rename your users template to _users
<script type="text/x-handlebars" data-template-name='_users'>
...
</script>
and then use the partial helper to render it
{{partial users}}
Note that {{partial}} takes the template to be rendered as an argument, and renders that template in place. This means that it does not change context or scope. It simply renders the given template with the current scope.
Hope it helps.

Categories

Resources