Getting undefined when using target '_blank' with ui-router - angularjs

Hi I'm having the below issue.
Below is my html page
<div class="content" ng-controller="DataController">
<table class="table table-striped" id="show" ng-if="datalist.length>0">
<thead>
<th>State</th>
<th>District</th>
<th>Non-DND's</th>
</thead>
<tbody>
<tr dir-paginate="data in datalist| filter:search|orderBy:sortKey:reverse|itemsPerPage:10" style="cursor:pointer;">
<td>{{data.state}}</td>
<td>{{data.district}}</td>
<td><a ng-click="getnre(data.nondnd,data.dnd,data.land,data.email)" ui-sref="numsemailsdata" target="_blank">{{data.nondnd.length}}</a></td>
</tr>
</tbody>
</table>
<dir-pagination-controls max-size="10" direction-links="true" boundary-links="true" style="float:right" ng-if="datalist.length>0">
</dir-pagination-controls>
</div>
Below is the code in my controller.js
app.controller("DataController", function($scope, DataService) {
$scope.datalist=DataService.getData();
$scope.getnre=function(ndnd,dnd,land,email) {
$scope.numsem = {
ndnds : ndnd,
dnds : dnd,
lands : land,
emails : email
}
}
});
Below is the numsdetails.html
<div class="content" ng-controller="DataController">
<table class="table table-striped">
<thead>
<th>Non-DND's</th>
</thead>
<tbody>
<tr ng-repeat="ndnd in numsems.ndnds">
<td>{{ndnd}}</td>
</tr>
</tbody>
</table>
</div>
Here I'm displaying the non-dnd's count in my first html page and I need to display the non-dnd's in new tab which is numsemails.html
When I'm trying to bind the data to numsemails.html, I'm getting the data as undefined even I'm binding the data from same controller.
Please help me with a solution.

The reason you are getting undefined for numsems is because when you open a new page (blank) you create an entire new instance of your app. It is like loading the page for the first time. Think of it as a totally different browser instance, because that is what it is. You can pass a parameter using stateparams, this gets passed in the url, however you are trying to pass an entire object so it becomes a bit more difficult.
There are multiple solutions to your problem. You can pass some data in the url, or you can use localstorage, $window, or cookies to store the data. I'm sure there are also other solutions. Choose one of these methods to hand your data properly and we can help you with it.
This issue has been discussed in other threads.
ui-router: open state in new tab with target=“_blank” with object params

Your controller code is wrong, you're missing brackets and braces:
app.controller("DataController", function($scope) {
$scope.datalist = DataService.getData();
$scope.getnre = function(ndnd,dnd,land,email) {
$scope.numsem = {
ndnds : ndnd,
dnds : dnd,
lands : land,
emails : email
};
}
});

Related

Datatables search, filter, and export with Firebase

I have a CRUD app powered by angular. Recently I added datatables to it in order to search, filter, sort,export and hide columns using the power of datatables. Unfortunately it returns the Firebase references in the various columns {{contact.name}} {{contact.email}} (There are 4 more columns) when I use any datatables feature such as search it returns the Firebase reference instead of a field. Is there a way to fix this? I really need those datatable features at the same time use Firebase.
$(document).ready(function() {
$('#contacts').DataTable( {
dom: 'Bfrtip',
buttons: [
'copyHtml5',
'excelHtml5',
'csvHtml5',
'pdfHtml5'
]
} );
} );
<table id="contacts" class="table table-striped table-hover" >
<thead>
<tr>
<th>Name</th>
<th>Phone</th>
<th>Area</th>
<th>Occupation</th>
<th>E-mail</th>
<th> Actions </th>
</tr>
</thead>
<tbody>
<tr ng-repeat="contact in contacts">
<td>{{contact.name}}</td>
<td>{{contact.phone}}</td>
<td>{{contact.area}}</td>
<td>{{contact.work}}</td>
<td>{{contact.email}}</td>
<td>Edit <a class="btn btn-raised btn-xs btn-danger" ng-click="removeContact(contact.$id)">Delete</a></td>
</tr>
</tbody>
</table>
EDIT
Will sourcing the data via ajax sort this out. This is the json format i get from the ajax GET request
{"-KIZ6VnucsKbKjlaE8aq":{"area":"Parklands","email":"tttt","name":"Mohammed Sohail","phone":"+254700000000","work":"ttt"},"-KId6OC2gOwiacUid9yK":{"area":"dfgdfg","email":"dfgdf","name":"dfg","phone":"dfgdfg","work":"fdfffffff"},"-KId6Rqo0B6w0jACHhWM":{"area":"dfgdfgdfgdf","email":"dfgdfgdfgdfg","name":"dfgfdgdf","phone":"gdfgdfgdfg","work":"gdfgdfgdfgdfg"},"-KIqmYZubPYhAqDqEyWo":{"area":"dfgfdg","email":"fgfdgfdgdf","name":"fgfg","phone":"fdgdg","work":"fgdfgdf"},"-KIqn5QABMXrTGoVgQv1":{"area":"bla","email":"weadasda","name":"bla","phone":"bla","work":"bla"}}
And this is how the data looks like on the console.
Any help to use data tables will be appriciated.
FireBase database image
So, this question is really about turning a (firebase) JSON object of objects with unknown object entry names such as KId6Rqo0B6w0jACHhWM into a more plain structure that can be used along with dataTables and ng-repeat?
You can format contacts into an array of plain objects this way :
$http.get('firebase.json').then(function(json) { //faked response from firebase
$scope.contacts = []
for (var item in json.data) {
$scope.contacts.push(json.data[item])
}
})
Now the ng-repeat will work and the markup (or contacts data) is understandable for dataTables. To turn this into angular-datatables (angular directives for jQuery dataTables) the only thing you need to do is to include the datatables dependency and include the datatable directive in the markup :
<table datatable="ng" class="table table-striped table-hover" >
demo -> http://plnkr.co/edit/tn9cuKa46vs4x8cHebjB?p=preview

Smart Tables Pagination Wont Work With Server Side Filtering

I have a smart table that I am working on in AngularJS. The table uses a custom pipe in order to search and sort its data. I also require that the table has working pagination, along with a drop down box so you can select the number of rows to be displayed (think datatables).
For searching and sorting, the custom pipe fires off my ajax requests without a problem. However, when I click on any of the page numbers or change the number of rows to show, the pipe is NOT fired.
The page numbers seem to be set to call setPage(page) (this is set by the st-pagination directive) but nothing happens - and no errors are thrown.
How do I get the custom pipe to fire upon changes to the number of rows displayed or when a page # is clicked in the pagination controls?
Here is my HTML:
<table class="table table-striped table-bordered" st-table="leadsCollection" st-safe-src="leads" st-pipe="serverFilter">
...
<tbody>
<tr data-toggle="modal" data-target="#modal-source" ng-repeat="source in leadsCollection" ng-click="rowClick($index);">
<td>{{source.leaddate}}</td>
<td>{{(source.distance > 100) ? 'Long Distance' : 'Local'}}</td>
<td>{{source.origin_city}}, {{source.origin_state}}</td>
<td>{{source.destination_city}}, {{source.destination_state}}</td>
<td>{{source.est_move_date}}</td>
<td>{{source.distance}} mi</td>
<td>{{source.number_bedrooms}} br</td>
<td></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="8">
<div class="form-group col-md-1">
<label>Show:</label> <select class="form-control" ng-model="itemsByPage"><option value="10">10</option><option value="25">25</option><option value="50">50</option><option value="100">100</option></select>
</div>
<div class="pull-right" st-pagination="" st-items-by-page="itemsByPage"></div>
</td>
</tr>
</tfoot>
</table>
And here is the controller:
.controller('Leads', function ($scope, $http) {
$scope.leads = [];
$scope.leadsCollection = [].concat($scope.leads);
$scope.itemsByPage = "10";
$scope.rowClick = function (idx)
{
$scope.editor = $scope.leads[idx];
}
$scope.serverFilter = function(tablestate)
{
$http.post("/portal/api/loadleads",tablestate).success(function(response){
console.log(response);
$scope.leads = response;
$scope.leadsCollection = [].concat($scope.leads);
});
}
})
In order to get smart tables to fire the filters off, you have to set the numberofpages on data load. To get the above filter to work simply add:
tablestate.pagination.numberOfPages = response.totalPages;
Smart Tables seems to require this to be set in order for it to properly bind the events.

ngTable updates ngClass result in error

I'm using esvit' ngTable. to display a big collectiong of data.
But when I try to add a ng-class(fn). First rendering it works (displays info class), but when I manipulate the data (as when i change the attribute winner on user (from the ng-click="(toggleWinner(user))"), it throws an error instead of updating the class.
ngTable:
<div ng-show="(answers).length > 0">
<table ng-table="tableParams" template-pagination="custom/pager" class="table table-striped table-bordered table-hover" style="margin-top: 12px;">
<tr style="cursor:pointer;" ng-click="toggleWinner(user);" ng-repeat="user in $data" ng-class="getClass(user)">
<td data-title="'Bruger'" sortable="'name'">{{user.name}}</td>
<td data-title="'Email'" sortable="'email'">{{user.email}}</td>
<td data-title="'Firma'" sortable="'company'">{{user.company}}</td>
<td data-title="'Mobil'" sortable="'mobile'">{{user.mobile}}</td>
<td data-title="'Vundet dato'" >{{getPreviousWinnings(user.email)}}</td>
<td data-title="'Udvælg Vinder'" >
<span ng-show="user.winner == true" class="glyphicon glyphicon-ok" style="color:darkgreen"></span>
</td>
</tr>
</table>
</div>
getClass(user):
$scope.getClass = function(user) {
if (user.winner) {
return "success";
} else if ($scope.getPreviousWinnings(user.email).length > 0) {
return "info";
} else {
return "";
}
};
I hope you can help, and thanks for taking a look
Error description:
TypeError: undefined is not a function
at Object.k [as fn] (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js:136:370)
at h.$digest (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js:106:311)
at h.$apply (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js:109:287)
at HTMLTableRowElement.<anonymous> (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js:189:372)
at HTMLTableRowElement.m.event.dispatch (local/js/libs/jquery-1.11.1.min.js:3:8436)
at HTMLTableRowElement.r.handle (local/js/libs/jquery-1.11.1.min.js:3:5146)
Most important thing first (solution):
Check your versions of libs to make sure they are the same
I was using angularjs 1.2.16 and angular-animate 1.2.10.
This resulted in angularjs calling it's own (it thought) $animate.setClass().
But in angular-animate 1.2.10 it is not there, and since I import the animate, it overwrites the $animate then there was no method to be called. Hard to see when using minified versions.
Anyways, thanks Kostia for making me make plunker so I could see it functioning.

Selector [ng\:model="test"] did not match any elements

I want to run an e2e-test using angular.
This is my html file:
<html>
<div>
<table class="table table-bordered">
<thread>
<tr>
.
.
.
<th class="icon">
<i ng-click="test" ng-show="isQuestionEditable()" class="icon-plus"></i>
</th>
</tr>
</thread>
</div>
</html>
How do I call ng-click properly?
I tried:
it('test', function(){
element('test').click();
});
But I get the error message: Selector [ng\:model="test"] did not match any elements.
I am accessing the right page for sure. I wrote:
beforeEach(function() {
browser().navigateTo('/');
});
'/' being proxied as http://localhost:8080/test
One work around would be to give the button an id="button" and then your selector would be element('#button').
Also check the caveat at the bottom of http://docs.angularjs.org/guide/dev_guide.e2e-testing
Its hard to tell from your example if you are manually bootstrapping angular or using ng-app.

How can I reuse a partial efficiently?

I am beginning to run into this problem a lot. The scenario is that I have a partial that I would like to reuse. The problem is, I would have to overwrite my previous data in the scope in order for the new data to show up in the partial. I would like to know how people get around this.
Here is an example:
I have tabs that all use $scope.pebbles and share the same partial. For each tab, I would like different data to be populated. So naturally, I would just make a new request for data and store it back into the variable to change the data, for example: $scope.pebbles = getPebbles(color). The problem with this is that I would have to make a new request each time I change the tab. Is there a better way around this without having a huge partial?
overview.html:
<tab>
<tab-heading>
<i class="icon-bell"></i> All
</tab-heading>
<div class="tab-content">
<div ng-include="'views/partials/_pebbles.html'"></div>
</div>
</tab>
<tab ng-repeat="color in colors">
<tab-heading ng-click="tab(color)">
{{color}}
</tab-heading>
<div class="tab-content">
<div ng-include="'views/partials/_pebbles.html'"></div>
</div>
</tab>
_pebbles.html:
<table class="table table-striped table-bordered bootstrap-datatable datatable">
<thead>
<tr>
<th>Pebble Name</th>
<th>Pebble Type</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="pebble in pebbles">
<td>{{pebble.name}}</td>
<td>{{pebble.type}}</td>
</tr>
</tbody>
</table>
Controller:
$scope.colors = ['blue','red','orange','purple']
$scope.pebbles = getPebbles() // http factory, makes a request for data
$scope.tab = function (color) {
$scope.pebbles = getPebbles(color)
}
A little bit of simplistic runtime caching will get you going:
Controller:
$scope.colors = ['blue','red','orange','purple']
// $scope.pebbles = getPebbles(); // http factory, makes a request for data
$scope.pebbles = [];
$scope.tab = function (color) {
$scope.selectedColor = color;
$scope.pebbles[color] = $scope.pebbles[color] || getPebbles(color);
}
Template:
<table class="table table-striped table-bordered bootstrap-datatable datatable">
<thead>
<tr>
<th>Pebble Name</th>
<th>Pebble Type</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="pebble in pebbles[selectedColor]">
<td>{{pebble.name}}</td>
<td>{{pebble.type}}</td>
</tr>
</tbody>
</table>
In the angular world, the way to share data across controllers / views is to use services. They persist between controllers.
I was about to write a nice answer, but I think the answer to this question is already complete.
Better design for passing data to other ng-view's and persisting it across controllers
Stewie's answer gets the job done effectively, but I wanted to suggest another design that you could potentially use.
Right now, your controller seems to be mixing two concerns; the management of your colors (tabs), and the management of the pebbles of a given color (tab contents).
What you could do instead is to have two controllers, each managing one of these concerns. This allows you to have controllers with clear cut roles and keeps your controllers slim. In the long run, it will keep your code maintainable as you add more functionality to your controllers. Here is a plunker where I have created an overviewController (dealing with tab management) and a pebblesController (dealing with individual tab content).
http://plnkr.co/edit/1ZP92VX0RljrsrfPpt0X?p=preview
**I faked the server-side getPebbles() http request and created "flat" tabs since I didn't want to bother with making actual tabbing.
Things to note with this implementation; it becomes more difficult to have dynamic tab loading (having tab-content load only upon being switched to for the first time), which Stewie's run-time caching example handles very well. In my plunker, all the tab-contents are loaded up-front. If you want to keep this design pattern and have dynamic tab loading, it would probably be cleanest to support it in the tabs directive itself, but that is out of the scope of this question.
So I'm guessing you're using Angular's UI-Bootstrap for modelling your tabs.
As Stewie suggested you could use a simple cache for caching your loaded tabs and as I understand you'd like to load your tabs on demand, when user activates them.
Checkout the little Plunkr I did, which does exactly that. I've used select expression to load the tab on change, either from cache or from backend.
The main code lives in a controller:
app.controller('PebblesCtrl', function ($scope, $http) {
$scope.colors = ['blue', 'red', 'orange', 'purple'];
$scope.pebbles = [];
$scope.loadPebbles = function (color) {
if (!$scope.pebbles[color]) {
console.log('loading "' + color + '" pebbles');
$http.get(color + '.json').then(function (response) {
$scope.pebbles[color] = response.data;
});
}
};
});
You can also display a place holder for your content
<tab ng-repeat="color in colors" heading="{{color}}" select="loadPebbles(color)">
<div ng-show="pebbles[color]">
<div ng-include="'_pebbles.html'"></div>
</div>
<div ng-hide="pebbles[color]">
Please Wait...
</div>
</tab>
It will be replaced when the data gets returned from the service.

Resources