I have to build an angularJS webapp and found many resource for best practice but there are still some questions that were not answered. I hope you can help me.
Question 1: Model
One thing is, where should i store my model and handle changes to it?
I found some different solutions but they were all for simple datastructures. I have something like User ---> Subscription ---> Device ---> HardwareReport. And this is just one branch of the datastructure tree.
My question is where should i store it so that every Controller can access the data.
Current solution:
Current solution would be, not to store the data structure but to have a service for every object type like UserService or SubscriptionService.
And every of these services handles the communication with the backend server and keeps the return value in a cache.
Downside:
If a controller needs for example all devices of the user it has to deal with all services and can't just go through the data-structure tree. What if one controller changes for example the device object of the user. How should i notify other controllers?
Question 2: lazy configure/instantiate services
Here is a part of the application.
I have an AppController, LoginController and a MapController.
And i have a BackendService which encapsulates the API-Calls and is used by UserService and SubscriptionService.
When i login into my webapp the LoginController uses the SessionService to verify the login data and receives an accessToken for the API.
This accessToken must be set in the BackendService to be added to the header.
But the BackendService is already injected in other services.
Current solution:
Just set the AccessToken from LoginController like
BackendService.setAuth(accessToken);
Because the service is singleton all other services that uses BackendService will be have the correct setup BackendService.
Downside:
I can call functions of the BackendService before setting the access token and this would result in errors.
** Alternative solution: **
I just implement a BackendServiceFactory which i can use at any time to create a new BackendService instance. So i can create the BackendService in the LoginController after login.
Downside: I have to pass this object through all my services and controller because it won't be injected by DI.
Quite long questions but i hope you can give me some suggestions how to build this app.
Related
Let's say, In a web app, a particular JSON is frequently used across multiple pages, for e.g:
{
"employees":[
{"firstName":"John", "lastName":"Doe"},
{"firstName":"Anna", "lastName":"Smith"},
{"firstName":"Peter", "lastName":"Jones"}
]
}
So getting a firstName() or lastName() for all employees should be considered as a part of the controller or the Service?
I could only think of using services as it is frequently used across app and controller be getting this data and it will be thinner too.
Is this right approach ?
You have following options:
Make a REST/HTTP call every time you need this data in a certain controller. Therefore, create a EmployeesService which calls the HTTP
endpoint to get the data.
Call the data once, and store it in a service. Afterwards, inject the service everywhere you need the data.
Fetch the data from the HTTP endpoint when your app starts, and store it in the local storage of the browser or inside the $rootScope,
so you can access it from everywhere.
In the end, it depends on:
How big is your app/how much data you have to share?
How often gets this data updated?
Which Views do need access to this data?
So yes, with a service, you are on a safe side. Afterwards, inject it into the controller and use it from there. How and how often the data gets into the service: Your decision.
I am a ASP.Net developer and trying to learn AngularJS. There are several ways to manage state in asp.net such as Session, ViewState, Cookies etc.
Can someone explain me or direct me to a good example which is showing state management best practices in angularJs.
For example once user log in to the application I want to store the current user object in client side.
There are many ways to maintain states. You can maintain a state, either using "$scope", or "$rootScope" in AngularJS.
For example :-
angular.module('SampleApp')
.controller('ExampleCtrl', ['$scope', '$rootScope', ExampleCtrl])
function ExampleCtrl($scope, $rootScope) {
// for set data
$scope.data="Hello";
$rootScope.Globaldata="Hello World";
}
In above example, "$scope" is used for page level or local variable and "$rootScope" is used for maintaining the state globally.
You can access the value of "$rootScope" anywhere in your application, whereas you don't use the value of "$scope".
Another way to store or to maintain data, is using LocalStorage:-
You can store your value using "angular-local-storage" and "ngCookies".
Follow Below Link :-
https://docs.angularjs.org/api/ngCookies/service/$cookies
You can use angular-local-storage, ngCookies to save states and provide persistence. Additionally you can use IndexedDB storage in newer browsers to provide persistence, with the condition that its not available in all the browsers.
A better strategy is to use combination of IndexedDB, localStorage, ngCookies with a fallback to in-memory storage. In order to do this you need to have a consistent api/ service which provides this functionality and handles the fallback gracefully within the service itself so that the consumer of the service doesn't need to bother about the fallback mechanism
Checkout this library https://www.npmjs.com/package/angularjs-store
This can help you manage your application state much simpler as it will force you to have a one way data flow on your application.
Ng-Cookies
You could add the Angular service ng-cookies this lets you store and retrieve cookies when you inject it into you module. Here is a link to the docs.
Add new service
To add a new service to you angular app you will first need to download the js files and add them too you index.html like (from CDN)
<script type="text/javascript" src=""//ajax.googleapis.com/ajax/libs/angularjs/X.Y.Z/angular-cookies.js""></script>
Load into app
In any module you want to use ng-cookies inject like this
angular.module('app', ['ngCookies']);
Conclusion
Your app now has access to the read and write cookie methods that come with ng-cookies But remember that the CookieStore service is depreciated so only use ng-cookie
from Angular Docs
Note: The $cookieStore service is deprecated. Please use the $cookies service instead.
Beyond this the Docs are pretty good. Best of luck.
There are a lot of ways in which this could be done. I use sample codes based on https://github.com/alarv/ng-login in my applications. I'm using tokens to authenticate the requests.
The sample code demonstrates
saving user information in a service called "Session".
2.statechangeEvents to handle authentication with roles.
interceptors to handle authentication/ authorization errors in http
requests.
If you are securing the html resources also, you might need to redirect the page to login page from the server side.
That highly depends on what kind of authentication mechanism you are using on back end.I use token based and session less systems for my projects so I use browsers local storage for storage of authentication tokens but if you are using sessions you will need to use cookies.
If you use local storage make sure you use JSON.stringify() first when saving and on retrieval of that Object make sure you use JSON.parse()
Disadvantage of localstorage : only html5 supported
So if your website needs to give support to older browsers you will need to have a fallback on cookies.
I have a server written in Express that interfaces with an application written in Angular on the client.
My Express server is receiving a post from a third-party service to a route which will perform business logic, and then here is where I am a little uncertain about the best path forward.
After receiving the post variables, I want to redirect the request to an Angular route, but I want to make those received post variables available to the route as well.
Somehow, I want to be able to mix the res.json() and res.redirect() method, but I'm pretty sure they both end the response.
What would be a logical way to structure this?
Update: To expand on the issue, imagine I have a route called /receivetransaction which receives some postback variables, including transaction ID, amount etc. I want to perform business logic (save to a database), and then redirect the user to /thankyou (an angular route) but have them be able to access that data that was just received in the postback.
It looks like maybe my best option would be to save to the database, and then send the transaction-id as JSON to the angular view, which will then hit the database and pull the info. A little inefficient though (not really a big deal) but I would hope there would be another way around it.
What I've decided to do is the following:
After the express route receives the postback variables, it performs the business logic (specifically saving the data to the database), and redirects the request to the angular route with a query var indicating the id of the transaction.
The angular controller uses $location.search() to pull the transaction id from the query var, and from there it performs a get request to the express API, which performs authentication and loads the relevant information into $scope variables to be passed to the view.
The Problem
The SharePoint adapter for Breeze expects a model with a SharePoint list name and then attempts by default to access _api/web/lists/getbytitle('<DefaultResourceName>') and I have not found a way to over ride that. The problem with this behavior is that if a user who is not a site collection admin accesses the User Information List using the web/lists/ end point they will receive a 404 error. Instead, for whatever reason, regular users must access the same exact information via _api/Web/SiteUserInfoList/items.
The Question
What would be the best way to add functionality to the Breeze SharePoint adapter to get user details or a list of site users? In my existing solution I have merely changed my data context object to use $http and the _api/Web/SiteUserInfoList/itemsend point but I'd like to still be able to use Breeze's amazing filtering ability but it's not clear to me the best path to begin adding this functionality to the adapter.
With breeze you can configure specific AJAX requests using a request interceptor.
The example below changes the timeout but you could just as easily change the url.
var ajaxAdapter = breeze.config.getAdapterInstance('ajax');
ajaxAdapter.requestInterceptor = function (requestInfo) {
requestInfo.config.timeout = 5000;
// todo: examine the requestInfo.config object and change the url as-needed
}
here's the relevant code in the breeze source
How would you structure the code for calling a wcf service in silverlight application?
Using only-once instanciated wcf service-proxy (aka singleton) and using it across the whole SL app?
If so, how did you solve the unsubscribing controls from ws-call-completed event?
or
creating the wcf service-proxy for each ws-call? Where do you close the proxy then?
Here's the application structure I found workable:
Application is split into modules (Prism but can be anything) - module per vertical function.
Every module has its own set of service client classes (generated by slsvcutil)
For every service client partial class I have another generated partial class where for every service method I have a version that returns IObservable.
E.g. if my service client has a method GetAllMyDataAsync() and event GetAllMyDataCompleted the generated method signature will be IObservable<MyDataDto[]> GetMyData() This method will deal with subscribing/unsubscribing to an event, authentication, error handling, and other infrastructure issues.
This way web-service call becomes simply:
new MyServiceClient().GetAllMyData().Subscribe(DoSomethingWithAllMyData)
With this I can easily join data from multiple requests, e.g. (strictly for demonstration purposes, don't try this in real app):
var des = (from d in new MyServiceClient().GetMyDataItem()
from e in new MyServiceClient().GetDataItemEnrichment(d)
select new EnrichedData { Data = d, Enrichment = e});
des.Subscribe(DoSomethingWithEnrichedData);
Once application gets more complex (e.g. data is shared by multiple components, you add messaging that dynamically updates initially retrieved data, etc.) it's helpful to add another element in the stack - Model.
Therefore if I have a service MyDataService I'd have a model class called MyDataServiceModel. It will be registered in the container as singleton and it will be injected into viewmodels that needs it. Thus viewmodels talk to this class when they need data (so rather than calling MyServiceClient.GetAllMyData it would call MyDataServiceModel.GetAllMyData.
This way viewmodels are completely independent of WCF stack (easier to mock, easier to test) Additionally these model classes take care of:
data transformation from/to DTO
enriching and combining data (one model method may join data from more than one request)
handling issues like throttling (e.g. typical scenario, user selected something in a combobox, it caused a request to be sent to a server to retrieve a data for that selection, while that request is being exected user made another change, but for some reason responses came out of order), etc.
combining data pulled on initial load via WCF with data pushed by the service during the session