I want to set a firestore collection in a service to later return an observable of its documents
#Injectable()
export class ContactService {
private contactCollection: AngularFirestoreCollection<any>;
private contactDocument: AngularFirestoreDocument<any>;
constructor(
private authService: AuthService,
private afs: AngularFirestore
) {
this.authService.user
.subscribe(user => this.contactCollection = this.afs.collection(`directories/${user.uid}/contacts`));
}
getContacts(){
return this.contactCollection.valueChanges()
}
this works fine if i navigate to the route that displays the component that consume the service but if i visit directly the route or refresh the page the contactCollection is undefined.
Any ideas why is this happening?
Related
I've used this as core project for one of my project and I am stuck with it.
I trying to use the http method but it fails.
I've tried add the HttpClientModule to the app.module but still nothing.
The error that i get is :
app.ae014c5e7b696f87de83.bundle.js:107 ERROR TypeError:
Cannot read property 'method' of undefined
All I did in the app.component.ts file add
export class AppComponent extends BaseComponent implements OnInit {
constructor(
private readonly i18nStore: Store<I18NState>,
private readonly config: ConfigService,
private http: HttpClient,
#Inject(PLATFORM_ID) public platformId: Object
) {
super();
// TODO: ngx-i18n-router
// private readonly i18nRouter: I18NRouterService) {
}
ngOnInit(): void {
this.i18nStore.dispatch(new Init(this.config.getSettings('i18n')));
}
createUserA(): void {
this.http.get<any>('https://swapi.co/api/people/1')
.subscribe(data => console.log('data', data));
}
}
Bot get and post don't work.
I've imported :
import { HttpClient } from '#angular/common/http';
Add to your app.component.ts
contructor(private http : HttpClient) {}
constructor(public navCtrl: NavController,public navParams : NavParams,
public modalCtrl:ModalController, private afAuth:AngularFireAuth, private afDatabase:AngularFireDatabase , public fb:FirebaseService) {
this.getDefaults();
this.selectedExercise=[];
console.log("home");
this.exercises=this.fb.getShoppingItems();
console.log(this.exercises);
at home.ts file,
at constructor, I get firebase data from firebase provider that I made to show it on list on html.
but the problem is that I logged it console.log(this.exercises) which is the data that I want to show on list, but it came null.
but after logged null, firebase provider get data from firebase and logged it
as you can see below.
I think browser should wait until firebase provider get data then should list it.
but don't know how to do it.
This is the way you should go
You need to change your getShoppingItems method to return a promise object like this
getShoppingItems(){
return new Promise<any>((resolve, reject) => {
this.db.list("/profile/user_id").subscribe(result =>{
resolve(result));
}
});
}
Your constructor method should get the result like this
constructor(
public navCtrl: NavController,
public navParams : NavParams,
public modalCtrl:ModalController,
private afAuth:AngularFireAuth,
private afDatabase:AngularFireDatabase ,
public fb:FirebaseService) {
this.getDefaults();
this.selectedExercise=[];
console.log("home");
//get your result like this
this.fb.getShoppingItems().then(result =>{
this.exercises = result;
console.log(this.exercises);
});
}
use the async pipe:
*ngFor="let item of exercises | async"
with
exercises = this.afd.list('...');
I am currently making an Ionic 2 application. I would like the user to be able to reorder a list of items that is displayed from the database. However, I keep getting this error:
TypeError: array.splice is not a function at reorderArray
There seem to be a problem with my FirebaseListObservable but I do not know what it is. Any help is much appreciated!
Below is my code for the following:
export class ManageFavouritesPage {
fireAuth: any;
items: FirebaseListObservable<any[]>;
constructor(public navCtrl: NavController, public af: AngularFire, private toastCtrl: ToastController, public authData: AuthData) {
let userid = this.authData.getID();
this.items = af.database.list(`/users/${userid}/favourites`)
console.log(this.items);
}
reorderItems(indexes) {
this.items = reorderArray(this.items, indexes)
}
I've created a gist highlighting the issue I'm running into. I'm using an Application Module to provide a Firebase dependency for me to inject elsewhere.
When I try to #Inject Firebase mFirebase in the data layer that dependency is never satisfied.
I'm trying to keep the Context out of my other layers, but the Firebase service depends on it. I'm interested in learning any other patterns to help keep Android classes out of my business logic.
FirebaseService.java
public class FirebaseService {
#Inject Firebase mFirebaseRef; //NEVER GET'S INJECTED!
#Override
public LoginResult signinWithEmail(final String email, final String password) {
mFirebaseRef.dostuff(); //THIS REFERENCE DOESN'T GET INJECTED!
}
}
ApplicationModule
#Provides
#Singleton
Firebase provideFirebase(#ApplicationContext Context context) {
Firebase.setAndroidContext(context);
return new Firebase(Util.FIREBASE_URL);
}
ApplicationComponent
#Singleton
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
#ApplicationContext Context context();
Application application();
Firebase firebase();
}
MyActivity
public class MyActivity extends AppCompatActivity {
private ActivityComponent mActivityComponent;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public ActivityComponent getActivityComponent() {
if (mActivityComponent == null) {
mActivityComponent = DaggerActivityComponent.builder()
.activityModule(new ActivityModule(this))
.applicationComponent(MyApplication.get(this).getComponent())
.build();
}
return mActivityComponent;
}
The full code example is on github
Annotating a field with #Inject is not enough for the field injection to work. There's no magic involved, you just have to tell Dagger to do the injection.
First, add this method to your ApplicationComponent:
void inject(FirebaseService firebaseService);
Then, call this method from your FirebaseService (I guess it's an Android service, so add this to the onCreate method):
applicationComponent.inject(this);
This should do the trick. There's a great answer to a similar problem here.
EDIT
I've looked at your repository and I think you don't even need field injection in this case. You can just provide the Firebase dependency through a constructor. Here's your #Provides method:
#Provides
#Singleton
LoginService provideLoginService() {
return new FirebaseLoginService();
}
Add Firebase as a parameter to it and pass it to the FirebaseLoginService constructor:
#Provides
#Singleton
LoginService provideLoginService(Firebase firebase) {
return new FirebaseLoginService(firebase);
}
The constructor:
public FirebaseLoginService(Firebase firebase) {
this.mFirebaseRef = firebase;
}
Remove the #Inject annotation from your mFirebaseRef field since it's not needed anymore.
Here's the corresponding pull request.
Using Dropwizard Authentication 0.9.0-SNAPSHOT
I want to check the credentials against database user (UserDAO).
I get the following exception
! org.hibernate.HibernateException: No session currently bound to
execution context
How to bind the session to the Authenticator?
Or are there better ways to check against the database user?
The Authenticator Class
package com.example.helloworld.auth;
import com.example.helloworld.core.User;
import com.example.helloworld.db.UserDAO;
import com.google.common.base.Optional;
import io.dropwizard.auth.AuthenticationException;
import io.dropwizard.auth.Authenticator;
import io.dropwizard.auth.basic.BasicCredentials;
public class ExampleAuthenticator implements Authenticator<BasicCredentials, User> {
UserDAO userDAO;
public ExampleAuthenticator(UserDAO userDAO) {
this.userDAO = userDAO;
}
#Override
public Optional<User> authenticate(BasicCredentials credentials) throws AuthenticationException {
Optional<User> user;
user = (Optional<User>) this.userDAO.findByEmail(credentials.getUsername());
if ("secret".equals(credentials.getPassword())) {
return Optional.of(new User(credentials.getUsername()));
}
return Optional.absent();
}
}
The Application Class
#Override
public void run(HelloWorldConfiguration configuration, Environment environment) throws Exception {
final UserDAO userDAO = new UserDAO(hibernate.getSessionFactory());
environment.jersey().register(new AuthDynamicFeature(
new BasicCredentialAuthFilter.Builder<User>()
.setAuthenticator(new ExampleAuthenticator(userDAO))
.setAuthorizer(new ExampleAuthorizer())
.setRealm("SUPER SECRET STUFF")
.buildAuthFilter()));
environment.jersey().register(RolesAllowedDynamicFeature.class);
//If you want to use #Auth to inject a custom Principal type into your resource
environment.jersey().register(new AuthValueFactoryProvider.Binder(User.class));
environment.jersey().register(new UserResource(userDAO));
To get auth to work with 0.9+ you need the following. You can refer to this particular changeset as an example.
Include the dependency.
<dependency>
<groupId>io.dropwizard</groupId>
<artifactId>dropwizard-auth</artifactId>
<version>${dropwizard.version}</version>
</dependency>
Register auth related stuff.
private void registerAuthRelated(Environment environment) {
UnauthorizedHandler unauthorizedHandler = new UnAuthorizedResourceHandler();
AuthFilter basicAuthFilter = new BasicCredentialAuthFilter.Builder<User>()
.setAuthenticator(new BasicAuthenticator())
.setAuthorizer(new UserAuthorizer())
.setRealm("shire")
.setUnauthorizedHandler(unauthorizedHandler)
.setPrefix("Basic")
.buildAuthFilter();
environment.jersey().register(new AuthDynamicFeature(basicAuthFilter));
environment.jersey().register(RolesAllowedDynamicFeature.class);
environment.jersey().register(new AuthValueFactoryProvider.Binder(User.class));
environment.jersey().register(unauthorizedHandler);
}
A basic authenticator
public class BasicAuthenticator<C, P> implements Authenticator<BasicCredentials, User> {
#Override
public Optional<User> authenticate(BasicCredentials credentials) throws AuthenticationException {
//do no authentication yet. Let all users through
return Optional.fromNullable(new User(credentials.getUsername(), credentials.getPassword()));
}
}
UnAuthorizedHandler
public class UnAuthorizedResourceHandler implements UnauthorizedHandler {
#Context
private HttpServletRequest request;
#Override
public Response buildResponse(String prefix, String realm) {
Response.Status unauthorized = Response.Status.UNAUTHORIZED;
return Response.status(unauthorized).type(MediaType.APPLICATION_JSON_TYPE).entity("Can't touch this...").build();
}
#Context
public void setRequest(HttpServletRequest request) {
this.request = request;
}
}
Authorizer
public class UserAuthorizer<P> implements Authorizer<User>{
/**
* Decides if access is granted for the given principal in the given role.
*
* #param principal a {#link Principal} object, representing a user
* #param role a user role
* #return {#code true}, if the access is granted, {#code false otherwise}
*/
#Override
public boolean authorize(User principal, String role) {
return true;
}
}
Finally use it in your resource
#GET
public Response hello(#Auth User user){
return Response.ok().entity("You got permission!").build();
}
You're going to need code in your Application class that looks like this
environment.jersey().register(AuthFactory.binder(new BasicAuthFactory<>(
new ExampleAuthenticator(userDAO), "AUTHENTICATION", User.class)));
Then you can use the #Auth tag on a User parameter for a method and any incoming authentication credentials will hit the authenticate method, allowing you to return the correct User object or absent if the credentials are not in your database.
EDIT: Works for Dropwizard v0.8.4
On Latest versions starting from 0.9 onward, you can use "#Context" annotation in resource class methods as shown below:
#RolesAllowed("EMPLOYEE")
#Path("/emp")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getEmployeeResponse(#Context SecurityContext context) {
SimplePrincipal sp = (SimplePrincipal) context.getUserPrincipal();
return Response.ok("{\"Hello\": \"Mr. " + sp.getUsername() + "\"( Valuable emp )}").build();
}