I cant seem to find a way with the NgRx (not RxJS Style) to dispatch 2 Actions in an effect.
I would like to (IN THIS ORDER):
delete a Movie in the Database with an effect,
dispatch deleteMovieSuccess
dispatch getMovies (I need to reload all Movies afterwards!)
I tried to do it like below, but it just fires the first Action, and I cannot see the other action:
In my log I can see:
[Movie list] Delete movie
[Movie list] Get movies
[Movie list] Get movies successful
I have the folloing actions:
export const getMovies = createAction('[Movie List] Get Movies', props<{search: string, page: number, limit: number}>());
export const getMoviesSuccess = createAction('[Movies List] Get Movies Success', props<{ search: string, page: number, limit: number }>());
export const deleteMovie = createAction('[Movie List] Remove Movie', props<{ movieToDelete: Movie, search: string, page: number, limit: number }>());
export const deleteMovieSuccess = createAction('[Movie List] Remove Movie Success', props<{ movieToDelete: Movie }>());
and the following effect:
deleteMovie$ = createEffect(() => this.actions$.pipe(
ofType(MovieActions.deleteMovie),
mergeMap(({movieToDelete, search, page, limit}) =>
this.moviesService.deleteMovie(movieToDelete)
.pipe(
map(() => MovieActions.deleteMovieSuccess({movieToDelete: movieToDelete})),
map(() => MovieActions.getMovies({search, page, limit})),
catchError(() => EMPTY)
)
)
)
);
How can I trigger BOTH, deleteMoviesSuccess, and getMovies in this order?
I`ve also tried with switchMap and and faltMap, but never are both Actions dispatched correctly.
I just cant seem to understand, how dispatching in an iterative way is possible, but I really need it for my special usecase.
Any help is greatly appreciated.
You should not dispatch two action in as a result of an effect. Rather dispatch some kind of success action and then react on that in other effects. Read here
You could create a chain of effect:
dispatch delete action
on finish of delete dispatch deleteSuccess action
on deleteSuccess action trigger loadMovies effect
on loadMovies success some set action for a reducer to pick up
deleteMovie$ = createEffect(() => this.actions$.pipe(
ofType(MovieActions.deleteMovie),
mergeMap(({movieToDelete, search, page, limit}) => this.moviesService.deleteMovie(movieToDelete).pipe(
map(() => MovieActions.deleteMovieSuccess({movieToDelete: movieToDelete})),
catchError(() => EMPTY)
))
));
loadMovie$ = createEffect(() => this.actions$.pipe(
ofType(MovieActions.deleteMovieSuccess),
mergeMap(() => this.moviesService.loadMovies().pipe(
map(movies => MovieActions.setMovies({ movies })),
catchError(() => EMPTY)
))
));
EDIT
Also instead of passing parameters like limit or search you may hold these in the store. Doing so gives you the advantage to always access those in effects when needed. The NgRx Documentation has a great example on how this selecting in an effect is done. ngrx.io/api/effects/concatLatestFrom
you could use the switchMap operator to return an array of actions.
For example, instead of;
deleteMovie$ = createEffect(() => this.actions$.pipe(
ofType(MovieActions.deleteMovie),
mergeMap(({movieToDelete, search, page, limit}) =>
this.moviesService.deleteMovie(movieToDelete)
.pipe(
map(() => MovieActions.deleteMovieSuccess({movieToDelete: movieToDelete})),
map(() => MovieActions.getMovies({search, page, limit})),
catchError(() => EMPTY)
)
)
)
);
You could try;
deleteMovie$ = createEffect(() => this.actions$.pipe(
ofType(MovieActions.deleteMovie),
mergeMap(({movieToDelete, search, page, limit}) =>
this.moviesService.deleteMovie(movieToDelete)
.pipe(
switchMap(() => [MovieActions.deleteMovieSuccess({movieToDelete: movieToDelete}),
MovieActions.getMovies({search, page, limit})]),
catchError(() => EMPTY)
)
)
)
);
Related
Construction like:
menu.add :label => current_admin_user.full_name do |submenu|
menus.each do |m|
submenu.add :label => m['name'],
:url => "/admin/change/#{m['id']}",
:html_options => {:style => 'float:left;'},
:if => proc { current_admin_user.role?('super_admin') }
end
end
Doesn't work in 1.0pre+ anymore. There is no current_admin_user in the scope. But in the logs i see the request that fetches admin user before a menu getting added.
SELECT `admin_users`.* FROM `admin_users` WHERE `admin_users`.`id` = 6 ORDER BY `admin_users`.`id` ASC LIMIT 1
Any chance to deal with it?
It is still possible to use, i only needed to pass id of a menu
menu.add id: 'user_name' label: -> { current_admin_user.full_name } do |submenu|
I have two screens:
Screen1: Results
Screen2: Edit Filters
When I edit the filters on Screen2 and press back, I would like to refetch the query on Screen1 (with the newly built filter string variable). Editing the filters doesn't use a mutation or fire any Redux actions (I'm storing the users search filters/preferences in localStorage/AsyncStorage instead of a database, so no mutation). I'm merely changing the local state of the form and use that to build a filter string that I want to pass to a certain query on Screen1. I have access to the filter string on both screens if that helps.
It seems like refetch() is limited to the component its query wraps http://dev.apollodata.com/react/receiving-updates.html#Refetch so how would I re-run the query from a different screen?
I tried putting the same query on both Screen1 and Screen2, then calling the refetch on Screen2, and although the query works and gets the new data on Screen2, the same name query doesn't update on Screen1 where I actually need it. Isn't it supposed to if they have the same name? (but the filters variable changed)
If I am just designing this incorrectly and there is an easier way to do it, please let me know. I expect that if I have 2 screens, put the same query on both of them, and refetch one of the queries with a new filters variable, then the refetch should happen in both places, but it's currently treating them individually.
I did the same thing here. The scenario:
- I choose a peer to filter some messages.
- I keep the peerId into redux
- I make both components (the filter and the list) dependent on that redux value.
Like this:
1 - To put that filter value on redux (and to grab it back):
import { compose, graphql } from 'react-apollo'
import { connect } from 'react-redux';
...
export default compose(
connect(
(state,ownProps) => ({
selectedMessages: state.messages.selectedMessages,
peerId: state.messages.peerId
}),
(dispatch) => ({
clearSelection: () => dispatch(clearSelection()),
setPeer: (peerId) => dispatch(setPeer(peerId))
})
),
graphql(
PEERS_QUERY,
...
when you call connect first (using compose), before you call a graphql wrapper, or outside that wrapper, you will have peerId available as a prop on your graphql wrapper, so you can use it to filter your query:
export default compose(
connect(
(state,ownProps) => {
return {
peerId: state.messages.peerId,
selectedMessages: state.messages.selectedMessages
}
},
(dispatch) => ({
toggleMessage(messageId) {
dispatch(toggleMessage(messageId));
}
})
),
graphql( // peerId is available here because this is wrapped by connect
MESSAGES_QUERY,
{
options: ({peerId}) => ({variables:{peerId:peerId}}),
skip: (ownProps) => ownProps.peerId === '',
props: ({
...
...
...
)(MessageList);
Realtime updates are kicking my ass! I have my entire fb app working except for this one area and I'm just not sure what I'm doing wrong.
My app is approved using these permissions:
"scope" => "offline_access,publish_stream,read_stream,user_location,user_status",
Next, I subscribe using these settings:
$subscribe = array( 'access_token'=> substr($my_access_token,13),
'object' => 'user',
'fields' => 'name,feed',
'callback_url' => $fbconfig['callback'],
'verify_token' => $fbconfig['secret']);
Via my app I post a status update on behaf of Bill Smith (userid: 000041143) and
that appears on Bill Smith's wall just fine. Next, using a an account for John
Doe (userid: 000004842 which has NOT authorized my app) I comment on the status post
made on Bill Smith's wall and this triggers the callback but what I'm getting (see below)
is an entry telling me that John Doe's wall has changed and no mention of Bill Smiths
wall is ever made.
Here's the notification given in the callback:
updates = Array
(
[object] => user
[entry] => Array
(
[0] => Array
(
[uid] => 000004842
[id] => 000004842
[time] => 1325101631
[changed_fields] => Array
(
[0] => feed
)
)
[1] => Array
(
[uid] => 000004842
[id] => 000004842
[time] => 1325101651
[changed_fields] => Array
(
[0] => feed
)
)
)
)
As you can see, this is not a notification that a comment has been made to Bill Smiths wall but that one has been made to John Doe's... I dont get this... I must be doing SOMETHING wrong!
I had similar issues before with photo IDs turning up 'wrong', the issue occurred because I was treating it as an INT but PHP was truncating it because it was too big, I had to treat it as a string. Could this be your issue perhaps?
I have been trying to read the news feed from a page that I have using an app that I'm coding.
Now I have had some issues trying to do this using the PHP SDK 3.0.
I am able to get the page information, but this is something that is publicly available any way.
My question is how do I get (read) the page wall posts? I'm assuming I have to grant permissions to my app to post to page, but how do I do this?
currently this is the code that I have
$appId = 'XXXXXXXXXXXXXXXXXX';
$secret = 'YYYYYYYYYYYYYYYY';
$pageId = 'ZZZZZZZZZZZZZZZZZZ';
$facebook = new Facebook(array(
'appId' => $appId,
'secret' => $secret
));
$pageProfile = $facebook->api($pageId);
$pagePosts = $facebook->api($pageId . '/posts/');
echo 'My Page profile';
print_r($pageProfile);
echo 'My Page wall';
print_r($userPosts);
Under 'My Page wall' I don't get anything. I don't get any errors either.
To access the posts of a page, it is /feed and not /post. Then, here is the correct version of your example :
require "facebook.php";
$facebook = new Facebook(array(
'appId' => YOUR_APP_ID,
'secret' => YOUR_APP_SECRET,
));
$pageFeed = $facebook->api(THE_PAGE_ID . '/feed');
Then the array $pageFeed will contain the 25 latest posts and links to navigation :
Array(
[data] => Array(
[0] => Array(
[id] => ...
[from] => ...
[to] => ...
[message] => ...
[icon] => ...
[type] => ...
[application] => ...
[created_time] => ...
[updated_time] => ...
)
[1] => ...
[2] => ...
...
[24] => ...
)
[paging] => Array(
[previous] => https://...
[next] => https://...
)
)
Hope that helps !
I know this is old, but I'll bring it up again! I just spent the last three days busting tail and trying to hack and crack the PHP SDK and Graph API, and I've done alright! I posted a full length lab with code and descriptions on my page, and you can view it below and ask me any questions you might have.
Basically, page feed is in a "graph" of info, or a super array. You use the app to connect to the facebook page, and get the feed. Connecting to a page's feed requires no permission from the page, hence why all you need is your APP ID, APP SECRET, and PAGE ID. The SDK automatically generates the APP ACCESS TOKEN for you, so you'r good there.
From then on, it's just about manipulating the graph. I've learned that Facebook feed has different types of posts. some are "photo", "message", "link". Anyways, check out the lab and tell me what you think.
http://www.callmenick.com/labs/displaying-a-custom-facebook-page-feed
Here is a model that I'm using, I've simplified it a bit down to the simplest form that still fails my example:
class User < ActiveRecord::Base
after_create :setup_lists
def setup_lists
List.create(:user_id => self.id, :name => "current")
List.create(:user_id => self.id, :name => "master")
end
end
And I'd like to spec the example as follows:
require 'spec_helper'
describe User do
before(:each) do
#user = Factory(:user)
end
describe "#setup_lists" do
before(:each) do
List.stub(:create).with(:name => "current")
List.stub(:create).with(:name => "master")
it "creates a new master list" do
List.should_receive(:create).with(:name => "master")
end
it "creates a new current list" do
List.should_receive(:create).with(:name => "current")
end
end
end
Which I expected would work just fine, but I am left with the following error:
Failures:
1) User#setup_lists creates a new master list
Failure/Error: List.should_receive(:create).with(:name => "current")
(<List(id: integer, name: string, created_at: datetime, updated_at: datetime, user_id: integer) (class)>).create({:name=>"current"})
expected: 1 time
received: 0 times
# ./spec/models/user_spec.rb:44
2) User#setup_lists creates a new current list
Failure/Error: List.should_receive(:create).with(:name => "master")
(<List(id: integer, name: string, created_at: datetime, updated_at: datetime, user_id: integer) (class)>).create({:name=>"master"})
expected: 1 time
received: 0 times
# ./spec/models/user_spec.rb:48
Can anybody help me understand why this is happening?
Three issues:
1) The User object is created before setting the message expectation, so should_receive never gets to see the message;
2) You're stubbing out methods for which you're also setting expectations. You want to stub out methods for which you don't set expectations, but which are needed for the test to pass
3) You need to pass in all the parameters
To fix, create the User object after setting the expectaion, and stub out each method in turn (because your model calls List.create twice):
describe User do
describe "#setup_lists" do
it "creates a new master list" do
List.stub(:create).with(:user_id=>1,:name => "current")
List.should_receive(:create).with(:user_id=>1,:name => "master")
#user = User.create
end
it "creates a new current list" do
List.stub(:create).with(:user_id=>1,:name => "master")
List.should_receive(:create).with(:user_id=>1,:name => "current")
#user = User.create
end
end
end
While it's really an issue of style, it makes more sense to use a real User object here rather than a factory, since you're testing the model itself.
zetetic's answer is awesome, but if you want something a bit quicker (and still works), I'd recommend using the shoulda-callback-matchers gem. It's a complete set of matchers that make testing callbacks easier. I'm all about easy & reducing boilerplate. You can see some examples in my RSpec model testing skeleton if you care to look.
Either way gets the job done!