ag-grid + angularJS header and cells editable by the user - angularjs

I just start using the ag-grid library with angularJS to display some tabular data in my application. The thing now is that I want the user to be able to alter the header value of each column like as he/she can edit the cells within a column when we enable the editable attribute. While searching for a solution I realized that there is no default way to turn the header into an editable element. So I was wondering which are my alternatives.
One thought of mine was to add to each header an edit button and when clicked a modal window to pop up with the corresponding input fields of the header and its column's cell values. In this case, the editable attribute is not going to be used because the edit of the cells will be conducted within the modal. Something like that but instead for the row, the button should be in each header.
So which are the ways that I can achieve something like that? I read about header template but couldn't really found any straightforward way to approach it.
Any ideas/hints or other alternatives are welcome.

Make a service which have an array as DataSet of your grid, and provide it with handlers for the events of a CRUD in the same service. Inject the service into the controller of your modal and view of the grid. After that, call the object gridDataSetadd,remove,update who is in the service, then $digest do the rest of the work once DataSet will be modified.
UPDATE, answering the comment
Inject your service into your controller:
For .ts
static $inject = ['$scope','YourService'];
constructor($scope, userService: YourService) {
this.userService.getSomething();
}
For .js
.controller('YourCtrl', ['$scope', 'YourService', function ($scope, YourService) {
$scope.someVar = YourService.someVar;
}])

Related

Retain Tab number in Navigation AngularJs

So I am relatively new to AngularJs and I am trying to figure out the best way for a tabController to remember what tab was previously clicked when switching to a new controller. So the situation would be I have 3 tabs. I click on tab 3 and then I click on something inside of it bringing me to a new controller and HTML template... What is the best way if I hit a "back" Button I created in that controller to remember exactly the state of it being the 3 tab.
I tried using $rootScope and then in each controller setting the tab number and setting the tabcontroller = $rootScope... but that was chaotic and too repetitive, and its not the right way.
This is not about $windoe.back(), this refers to coming up with a way that no matter where the navigation is the tab number is retained.
You can use a factory for this. In angular, a factory is a singleton, meaning only one instance of it exists for the whole project. Thus, by making something with it in one controller (and saving what you've did), you can access your changes in another controller.
angular.module('awesomeApp')
.factory('tabHistoryFactory', function () {
var tabHistory = {
setPrevTab: function(tab) { tabHistory.prevTab = tab; },
getPrevTab: function() { return tabHistory.prevTab; }
};
return tabHistory;
});
Then, in your first controller you'll have to inject this factory and before changing to another tab, just save the tab you're on using tabHistoryFactory.setPrevTab(tab). Then, in your second controller, you can access your previous tab by using tabHistoryFactory.getPrevTab(). Similarly, you can customize the behavior of your tab history by implementing other functions alongside those two.
Good luck!

Angular - How can I clear factory variables when the view changes?

I'm fairly new to angular, so bear with me. :-)
I have a list of contacts in one view. I put together a service with some setter and getter functions to hold the contact ID. When the user clicks a contact on the list view, it sets the ID in the service and moves to the edit form view. This is working well, but when I'm done editing and click to go back to the list view I want to clear the variables in the service. How would I do that?
I found one other answer on this topic, but I think it's using the built in angular router instead of ui-router.
Angular updating and clearing factory variables
Also, wouldn't the method in that answer also clear the variables when the user moved from the list to the edit form in the first place?
Thanks!
If it's a route change you can use $locationChangeStart, see $location
For example in your edit controller, register for the event on route change:
var onloc = $scope.$on('$locationChangeStart', function (event, newUrl, oldUrl) {
myService.cleanUp(whatever);
onloc();
});

Sharing data from multiple instances of a directive

I have a custom directive which is re-usable throughout the application. This directive uses ui-grid and I'm trying to determine the "angular way" of allowing access to the grid API from anywhere in the application.
If it was only a single instance, I'd use a service to share data across controllers:
var attachments = angular.module('attachments', ['ui.grid']);
// this would be accessible from any of my controllers
attachments.factory('Attachments', function() {
return {};
});
attachments.directive('attachments', function() {
return {
restrict: 'E',
templateUrl: 'attachments.html', // template has a ui-grid, among other elements
controller: ['$scope', 'Attachments', function($scope, Attachments) {
$scope.gridOptions = {
// ui-grid code here
onRegisterApi: function( gridApi ) {
Attachments.grid = gridApi;
}
};
}]
};
});
However, there could be multiple instances of the directive
For example, there might be a primary instance of this directive and one inside a modal, or one in a sidebar, one in a modal, etc.
I suppose I could add property namespaces to that service...
Attachments = {
libraryGrid: // ...
someModalGrid: // ...
}
etc...
I'd prefer to avoid making a service for each possible instance, i.e.:
attachments.factory('SomeModalAttachments', function() {
return {};
});
While it would work it feels inefficient. However, both choices are a lot better than digging into the modal scope and finding child scopes with the necessary API.
Is there any other method I haven't considered?
To me it depends on your usage model.
If you're going to have multiple of these and other bits of the application are going to access them, then that means one of a few things:
The access is actually initiated from the grid. So you have perhaps many list pages, and the currently active list page is the one you want to deal with. So I'd have the grid register with all the things it wants to talk to, and deregister when it closes again. The other things would all be services (singletons).
There are a specified number of these grids, and you talk to them by name - so you want to interact with the list-page-grid, or the modal-grid or whatever. So you have each grid register with somewhere central (maybe a service that everything else talks to).
The grids are subsidiary to something. So a page includes the grid directive, and then that page wants to talk to that grid. You could pass an object into the directive, then have the grid register itself on that object. So you call the directive with "myGridCommunicationObject = {}", and then the grid does "$scope.myGridCommunicationObject.gridApi = gridApi". This doesn't let other bits of the application talk to the grid, but if really you only want whatever created the grid to talk to it, then it works well.
You could broadcast. So if you don't really care which grid you talk to, you just want to talk to any grid that's currently visible (say you're resizing them or something) you could just broadcast an event to them, and all your grid directives could listen for that event. Taking this one step further, you could broadcast and include a grid id or name in the parameter, and then have each grid check whether it's me before taking action.
Having said all those options, there's something about what you're doing that has a bit of a code smell to it. Really, arbitrary bits of the application shouldn't want to talk directly to the grid Api, they should be communicating with methods on the controller that holds the grid. Perhaps some examples of what you want to do would help, but it feels to me like the model should be one of the grid registering to use other services (e.g. resize notifications), or of the controller that owns the grid interacting with the grid, and other things interacting with that controller.

Best practices for adding/editing data using AngularJS

I am currently developing an SPA application using AngularJS which allows end-users to add & edit orders via a form.
What I would like to know is what is considered the best practice for determining whether the application is in an Edit or Create state?
For example, when I click on a menu item that says 'Add New Order' I would expect a partial view called `order.html' displayed with all entry fields blank. If it's possible, I would also like is to re-use this same view when editing an order with the entry fields pre-filled from the current order being edited.
Do I need to use a service/factory for this that has a property to determine state, for example:
angular.module('app')
.factory('orderService', ['$http', function($http) {
var state = {
addOrder: false,
order: {
orderRef: "",
orderDate: ""
}
};
}]);
Then I could set the addOrder property from the relevant controller according to the edit state, as well as filling out the order property with the details of the order when addOrder: true.
I have looked around the net, unfortunately such examples of this appear to be scarce.
I am currently using a service (DataRepo) which stores all the data you want to keep globally. For example, you have an input where users can type in some side notes regarding their order and they might to see their text again if they navigate back to this very site.
<input type="text" ng-model="DataRepo.orderNotes">
In your controller, you inject your DataRepo service and bind it to the scope:
$scope.DataRepo = DataRepo;
By doing so, user input will be automatically stored into the DataRepo service.

Opening angular-ui-bootstrap modal from javascript

I am trying to open the modal dialog from javascript when a certain condition is met. The example shown here http://angular-ui.github.io/bootstrap/ invokes the modal on ng-click.
How do I achieve showing modal when a certain condition is met?
Thanks
Additional Info
Sorry didn't mean to create confusion. I am going to clarify a little bit more by saying what I meant by "certain condition". The scenario is the user will search for customer by name and will get a list of customers back matching with the search string. The user then clicks on any one of the customer row to get more detail information.
When clicked the code control is handed off to Controller (It's an ASP.Net MVC app) which will then go through other classes and finally get data of the customer from database. It will then populate a boolean property called spouseNotFound. It then returns the JSON back to angularjs controller. Now assume that if this particular customer does not have spouse I want to show a modal saying that "Spouse not found".
So, no, I don't want the modal to be invoked on an event, rather than on business rule condition.
Hope that helps to understand things clearly.
Straight from the documentation.
$modal is a service to quickly create AngularJS-powered modal windows. Creating custom modals is straightforward: create a partial view, its controller and reference them when using the service.
Example plnkr. (http://plnkr.co/edit/?p=preview)
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl,
resolve: {
items: function () {
return $scope.items;
}
}
});
If anyone needs an easy approach to showing Bootstrap Modals with AngularJS, then you can simply use the following approach. It worked well for me:
var element = angular.element('#myModal');
// Open dialog
element.modal('show');
// Close dialog
element.modal('hide');
What you may be looking for is a $watch on your scope. This will allow you to monitor a variable, and when the value is what you want, then launch the modal as Nix describes.
$scope.$watch('entities', function(){
if($scope.entities[0].checked && $scope.entities[1].checked){
alert("If I were bootstrap, I'd be launching a modal right now!");
};
}, true);
A jsfiddle: http://jsfiddle.net/HB7LU/1636/

Resources