How do I override/replace the DefaultDataService in NgRx and write custom API methods - ngrx

Hi I'm having trouble using a custom API call with NgRx Data. I am trying to use my own custom call in the EntityService but it isn't working
Instead of this:
getAll(): Observable<T[]> {
return this.execute('GET', this.entitiesUrl);
}
I need something that NgRx Data can use like this:
getAllTournaments(params?: any): Observable<Tournaments[]> {
return this.http.post(`${API}/.../...`, params).pipe(
map(result => result)
)
}

Related

Unable to mock FullCalendar's getApi() that returns a mock Calendar (Angular & Jasmine, Karma)

I'm trying to write test cases around a component that contains my FullCalendar component in Angular.
I've written karma tests using a MockFullCalendar that extends FullCalendar and have been successfully able to mock the getApi().view calls for getting fake active start and active end dates. But when I use the same method for getApi().getResources() and getApi.getResourceById(id) I get this error when running tests
error TS2339: Property 'getResourceById' does not exist on type 'Calendar'.
const calendarResource = this.calendar.getApi().getResourceById(resourceIdAssignedToEvent);
Here are my mock classes
export class MockFullCalendarComponent extends FullCalendarComponent {
getApi(): any {
return {};
}
}
export class MockCalendarApi extends CalendarApi {
getResources(): any {
return [];
}
getResourceById(resourceId: any): any {
return {};
}
}
export class MockCalendar extends MockCalendarApi {
get view(): any {
return {
get activeStart(): any {
return new Date();
},
get activeEnd(): any {
return new Date();
}
};
}
}
The following is how I was able to successfully mock the getApi().view
export class MockFullCalendarComponent extends FullCalendarComponent {
getApi(): any {
return {
view: {
activeStart: new Date(),
activeEnd: new Date()
}
};
}
}
Using the same pattern somehow does not work for the Calendar and CalendarApi classes. I'm not sure if this is because there is a class and an interface of the same name (CalendarApi) in FullCalendar common and only the interface contains these two methods.
I'm using Angular 12 and FullCalendar V5.
I've tried mocking as described above, tried different ways to provide my mock classes to the TestBed for injection.
My test case does not run at all, because these methods aren't detected somehow, none of the existing tests run at all, its almost like the whole initialization of the test case fails at this and I'm not sure how else I can force the spec to use my mock classes that contains mock implementations of those methods.

Having issues getting the notification feed for new follows when using stream-laravel

I am building a small project using Getstream Laravel package. However I am having a problem trying to display notifications for new followers. I get an empty result set when I call \FeedManager::getNotificationFeed($request->user()->id)->getActivities() in a controller method. I have my follow model looking like this:
class Follow extends Model
{
protected $fillable = ['target_id'];
public function user()
{
return $this->belongsTo(User::class);
}
public function target()
{
return $this->belongsTo(User::class);
}
public function activityNotify()
{
$targetFeed = \FeedManager::getNotificationFeed($this->target->id);
return array($targetFeed);
}
}
Then the controller action to get the notifications for new follows looks like this:
public function notification(Request $request)
{
$feed = \FeedManager::getNotificationFeed($request->user()->id);
dd($feed->getActivities());
$activities = $feed->getActivities(0,25)['results'];
return view('feed.notifications', [
'activities' => $activities,
]);
}
In the user model I have defined a relationship that a user has many follows. And lastly the follow and unfollow actions in the FollowController look like this:
public function follow(Request $request)
{
// Create a new follow instance for the authenticated user
// This target_id will come from a hidden field input after clicking the
// follow button
$request->user()->follows()->create([
'target_id' => $request->target_id,
]);
\FeedManager::followUser($request->user()->id, $request->target_id);
return redirect()->back();
}
public function unfollow($user_id, Request $request)
{
$follow = $request->user()->follows()->where('target_id', $user_id)->first();
\FeedManager::unfollowUser($request->user()->id, $follow->target_id);
$follow->delete();
return redirect()->back();
}
Not sure if there's something I left out but I can't get results for the notification feed. If I head over to the explorer tab from the Stream dashboard, I can see that I got two new follows which generated both timeline and timeline_aggregated type of feed. Or how should I get the notification feed from a controller action? Thanks in advance
The \FeedManager::followUser method create a two follow relationships: timeline to user and timeline_aggregated to user.
In this case what you want to create a follow relationship between notification and user. Something like this should do it:
\FeedManager:: getNotificationFeed($request->user()->id)
.followFeed('user', $follow->target_id)

React Native persisting user data

In my app I have 2 components (Page and Home).
Home extends Page like so:
export default class Home extends Page
and Page just extends Component.
In Page I have a method to get user data from AsyncStorage
async getUser() {
// get from storage
this.setState({user});
}
The above is called on the constructor of Page.
The problem I have is that Home has a method on componentWillMount that relies on this.state.user. Obviously this isn't going to work since the getUser method is async.
Is there a way I can get the user information and only call specific methods once I have that info?
export default class Page extends Component {
async getUser() {
// get from AsyncStorage
this.setState({user});
}
componentWillMount() {
this.getUser();
}
}
export default class Home extends Page {
async foo(user_id) {
this.setState({something});
}
componentWillMount() {
this.foo(this.state.user);
}
render() {
return <Text>{this.state.something}</Text>;
}
}
Is there a way I can get the user information and only call specific
methods once I have that info?
Not in a general sense, but of course there are some solutions. What this comes down to is that you have an async data dependency. You need to write the code in such a way that a call to dependent functions is only made after the data becomes available.
Perhaps the easiest way to do this is to use componentWillUpdate instead of componentDidMount and check if you are receiving the required data:
componentWillUpdate(nextProps, nextState) {
if (nextState.user != null && this.state.user !== nextState.user) {
this.prepareForUser(nextState.user);
}
}
(Note that you can't setState directly in componentWillUpdate, but since your method is async it won't happen until later. You can use componentDidUpdate to chain another setState call.)
Another option (which I like to use) is to use composition instead of inheritance. This makes the life-cycle easier to control through rendering: the parent can only render a child when all the child's dependent data is loaded, then the child does not need to worry about any timing issues related to the initial loading of data and can do whatever it wants from its componentDidMount:
class UserContainer extends Component {
state = {};
componentDidMount() {
this.getUser();
}
async getUser() {
// get user from async store
this.setState({user});
}
render() {
return (
<div>
{ this.state.user ? <UserView user={this.state.user} /> : <Spinner /> }
</div>
);
}
}
class UserView extends Component {
componentDidMount() {
this.props.user != null
}
}
This is pretty much the "container component" pattern.

correctly setting up and using angular with asp.net-mvc

I'm trying to learn the correct way of using angular with asp.net-mvc. Right now what I'm doing is letting the asp.net engine render my views, but I'm not passing any information to the view as a model. I'm using ng-init to call a scope function to retrieve data as json.
for example my index view's get action method is as follows:
public ActionResult Index()
{
return View();
}
and I have another controller action method that angular calls:
public ActionResult getMembersList()
{
List<CommunityMember> cmList = new List<CommunityMember>();
var members = db.Member.OrderBy(x => x.FirstName).ToList();
foreach (var m in members)
{
CommunityMember cm = new CommunityMember(m);
cmList.Add(cm);
}
return Json(cmList, JsonRequestBehavior.AllowGet);
}
(as an aside, should I avoid this foreach loop? it just creates a list of my CommunityMember viewmodel)
and the angular function looks like this:
$scope.getMembersList = function () {
$http.get("/Members/getMembersList")
.success(function (data) {
$scope.membersList = data;
}).error(function (data) {
console.log(data);
});
};
also all my code for angular is currently in an angular controller:
var myApp = angular.module("myApp", []);
myApp.controller('myIndexViewModel', function myIndexViewModel($scope, $http, $compile) {
//scope functions/variables
//http calls
//etc..
}
I just feel like this isnt the best approach and want to know if theres a better way to do this. Should I be loading data the way I am through ng-init then using the injected $http to access the server?
should I put all the $http calls in a different place?
thanks for any help!
Inside foreach loop what you are making is converting a list of objects to another list of objects.This is so called mapping(projection) in functional programming and there is already a linq method to do that. Use Select,it is more concise.
var members = db.Member.OrderBy(x => x.FirstName)
.Select(x=>new CommunityMember(){
Name=x.Some,
Age=x.Age
}).ToList();
The code placed in the controller is not so good. Responsibility of the controller should be data and view not to call services using $http. Move the $http calls to a custom service that implements promise pattern to notify the controller.Now controller is free from any logic other than updating data that is on the UI.
Try to avoid using Razor for data rendering and keep your front view decocupled from Razor. Js ,html views can be hosted anywhere.You dont have to keep it .Net project too.Make your server side behave as Api layer for your angular application.So make your views static and let angular decide functionality.
Indeed ng-init isn't the best way of getting data from your backend. Instead, you have two other options.
The first one is to resolve getMembersList inside your route.
The second one is to resolve getMembersList inside your controller, update your scope and then hide your loader.
Option 1 (using UI-router) :
state('members', {
url: '/members',
templateUrl: 'someTemplateURL',
controller: function(members) {
//Do something here
},
resolve: {
members: function($http) {
return $http.get("/Members/getMembersList")
}
}
})
Option 2 (Inside Controller using controllerAs syntax and ES6 fat arrow) :
memberModule.controller('membersCtrl', function ($http) {
this.loader = true;
$http.get("/Members/getMembersList")
.success((data) => {
this.membersList = data;
this.loader = false;
//Your view will pick up the change after the next digest cycle
})
}

Facade pattern for Symfony2 services

New to Symfony2, I'm building an app that uses an external API to get data. I created a lot of client classes to retrieve and transform each entity from the API, and I defined those classes as services - e.g., I have a FooClient with methods like getAll() or getThoseThatInterestMe($me), which return data from the API.
Now I wanted to create a ApiClientFacade class, which acts as an interface in front of all the XxxClient classes, following the Facade Pattern - e.g., this facade class would have a method getAllFoo(), which in turn would call FooClient::getAll(), and so on...
I could define my facade class as a service as well, but it'd have too many dependencies - I have around 30 client classes. Also, afaik with this approach I'd be loading all 30 dependencies every time, while most of the times I'd only need one dependency...
So, is there a better way to do this?
Use additional ApiClientFactory to move responsibility about "instantiation of ApiClient objects" from your ApiFacade class (which is your initial idea, as I understood).
In some pseudo-php code my idea is:
$api = new ApiFacade(new ApiClientFactory);
$api->sendNotificationAboutUserLogin('username', time());
An example of method:
class ApiFacade {
private $apiFactory;
public function __construct(ApiClientFactory $factory)
{
$this->apiFactory = $factory;
}
public function sendNotificationAboutUserLogin($username, $timeOfOperation)
{
return $this->apiFactory
->createApi('User')
->post(
'notifications',
array('operation' => 'login', 'username' => $username, 'timeOfOperation' => $timeOfOperation)
);
}
}
In this case your Facade class stays injectable (testable), but also becomes simpler instantiatable (you don't need to pass all dependencies into it anymore).
The ApiClientFactory should look like that:
class ApiClientFactory {
private $apiBaseUrl;
public function __construct($apiBaseUrl)
{
$this->apiBaseUrl = $apiBaseUrl;
}
public function createApi($apiName)
{
switch ($apiName) {
case 'User': return new \My\UserApi($this->apiBaseUrl);
default: // throw an exception?
}
}
}

Resources