Escolar Documentos
Profissional Documentos
Cultura Documentos
Its not that easy to wrap your head around the whole state management of SPAs.
Theres not that much on the web about it & its such a needed concept when your
application grows. If you have a small app that doesnt take advantage of needing
components to talk to each other, then its not the time to start with ngrx/store. In my
applications that I build, when I need to rely on events in Ionic I think its time to look at
state management.
The setup
1. ionic start bigbeartechNgrx blank
2. cd bigbeartechNgrx
3. npm i --save @ngrx/store
4. ionic serve --lab
When you run all that then you should now have a blank Ionic Framework.
Now youre going to need something to change the state with..These are called
reducers! They get the payload from the actions, then return the state.
Create ./src/reducers/mealReducer.ts
Its looking good, but were missing one thing. How is angular going to know anything
about what a reducer is? Ahhhhh.we need to register it in the app.module.ts file in
imports.
Go to ./src/app/app.module.ts
But wait a min we can clean this up a bit cant we? How about we extract the call to
reducer & create ./src/reducers/reducers.ts
1. import { mealReducer } from "./mealReducer";
2. export const ROOT_REDUCER = {
3. meals: mealReducer
4. };
You dont have to create the file if you dont want to. But I always like to clean things up
a bit & the app.module.ts can get big in some projects if youre not using lazy loading.
Edit ./src/app/app.module.ts
Ok there is a lot of boilerplate code here, but its all needed in the long run.
Edit ./src/pages/home-page.ts
We use the dispatch on the store with the action that we created
called mealActions.ts .. The action will then send the payload to mealreducer, which
will take the payload and return it back to the state. Best of allits reactive! That means
that its using RxJS under the hood to subscribe & send the data. So, no more
subscribing to ionic events & updating arrays.
We have the backend about done, but what about the Ui? Its coming, dont think too far
in advance, absorb this information because its a lot to understand at first, but its easy
in the end.
Ok lets get down to the nitty gritty with what the user sees!
The form is just using [(ngModel)].which if this was a production app, you would
probably be using the formBuilder. What about the | async on the end? Its just telling
angular that the array is actually an Observable so this data can change.
The user fills out the form data, then they click the Add button, it then sends the click to
addMeal function, which the addMeal function will send an action to the reducer. The
reducer returns the state, then sends the data to store.select, which we tell it to get the
meals. Async now updates the list with a new meal.
This is the way I understand it & see it happening in my mind. It might not be exactly the
way it works. Im sure Im leaving out a lot of things its doing in the background. You
dont need to worry about how it works at first if you dont want to.
Just know that actions > reducers return state > Observables update view.
Hope this helps people & if you did learn a lot please share the post so it helps others.
@ngrx/store seems to have went through a lot of revisions, so all the blog posts out
there where already out of date.
ShareTweet
In the last blog post I showed you how to use ngrx/store in Ionic Framework. I got a
comment from someone who asked me how to use ngrx/store with a api backend. This
is going to be a real app with a Laravel Backend to manage the data & not a local
storage. This app will be based on meals. I know, I know Why dont you use books or
posts? LOL I just like the meal concept because of our Mealinvy App.
If you notice the extra store-devtools, well this is optional, but it really helps you see a
great overview of the state. You can also time travel in it, which that means you can go
back & forth in the state. You can use devtools on Google Chrome or Firefox.
1. <?php
2.
3. use Illuminate\Support\Facades\Schema;
4. use Illuminate\Database\Schema\Blueprint;
5. use Illuminate\Database\Migrations\Migration;
6.
7. class CreateMealsTable extends Migration
8. {
9. /**
10. * Run the migrations.
11. *
12. * @return void
13. */
14. public function up()
15. {
16. Schema::create('meals', function (Blueprint $table) {
17. $table->increments('id');
18. $table->string('title')->index();
19. $table->text('content');
20. $table->timestamps();
21. });
22. }
23.
24. /**
25. * Reverse the migrations.
26. *
27. * @return void
28. */
29. public function down()
30. {
31. Schema::dropIfExists('meals');
32. }
33. }
1. DB_CONNECTION=mysql
2. DB_HOST=127.0.0.1
3. DB_PORT=3306
4. DB_DATABASE=homestead
5. DB_USERNAME=homestead
6. DB_PASSWORD=secret
Run migration:
1. [Illuminate\Database\QueryException]
2. SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes
(SQL: alter table `users` add unique `users_email_unique`(`email
3. `))
1. <?php
2.
3. namespace App\Providers;
4.
5. use Illuminate\Support\Facades\Schema;
6. use Illuminate\Support\ServiceProvider;
7.
8. class AppServiceProvider extends ServiceProvider
9. {
10. /**
11. * Bootstrap any application services.
12. *
13. * @return void
14. */
15. public function boot()
16. {
17. Schema::defaultStringLength(191);
18. }
19.
20. /**
21. * Register any application services.
22. *
23. * @return void
24. */
25. public function register()
26. {
27. //
28. }
29. }
1. <?php
2.
3. Route::prefix('v1')->namespace('Api\V1')->group(function() {
4. Route::resource('meals', 'MealController');
5. });
1. <?php
2.
3. namespace App\Http\Controllers\Api\V1;
4.
5. use App\Meal;
6. use Illuminate\Http\Request;
7. use App\Http\Controllers\Controller;
8.
9. class MealController extends Controller
10. {
11. /**
12. * Show all the meals
13. *
14. * @return \App\Meal
15. */
16. public function index()
17. {
18. return Meal::all();
19. }
20.
21. /**
22. * Store the meal
23. *
24. * @param Request $request
25. * @return \App\Meal
26. */
27. public function store(Request $request)
28. {
29. $meal = new Meal;
30. $meal->title = $request->input('title');
31. $meal->content = $request->input('content');
32. $meal->save();
33.
34. return $meal;
35. }
36.
37. /**
38. * Delete a certain meal
39. *
40. * @param Meal $meal
41. * @return JSON
42. */
43. public function destroy(Meal $meal)
44. {
45. $meal->delete();
46.
47. return ['success' => true];
48. }
49. }
Really simple API index, store & delete. But are we missing something? When you call a
get to https://meals.dev/api/v1/meals what is it going to do? Well its going to fail
because of No Access-Control-Allow-Origin header is present this looks bad with
all the red in the console, but its actually really simple to fix.
Im going to use barryvdh/laravel-cors package & pull it in with composer. If you dont
have composer setup go to https://getcomposer.org/doc/00-intro.md
Run in you terminal, powershell or cmd inside of your Laravel project folder:
1. Barryvdh\Cors\ServiceProvider::class,
Are you glad were done with the API backend setup! Oh come on Laravel is fun to
work with! LOL!!!
Now, since this continues my last blog post were starting off from where we left off. If
you havent, you can go and complete all the steps at setting up
Ionic https://blog.bigbeartechworld.com/ionic-ngrx-store/
Since were working with a api now what is the first thing we need? I know its a
provider to keep the logic separate from the pages.
Create MealProvider:
You need to change https://meals.dev with your own url. Ok, we need to add another
action to store all the meals in the state at launch. If we dont populate the state at
launch, it will be out of sync.
Adding an action isnt all we need to do is it? No if you remember from the last post
the reducer is what we use to return the current state.
Why did I add created_at & updated_at to the Meal interface? Well, Laravel keeps up
with all the dates for you so it should be in the state if you want it.
Also we are using to MealActions.STORE_MEALS in the switch & just returning the
payload.
Go to your ./src/pages/home.ts:
We are using the MealProvider on the addMeal & removeMeal functions. Those are
calling the MealActions.AddMeal & MealActions.DeleteMeal which in the reducer is
handling the state, then returning it. If you installed the chrome devtools or Firefox
addon you can see how the state is updating & deleting.
If you have any questionsdont hesitate to comment. As always, if you learned a lot
please share it to your social networks so it can help others as well! Thank YOU!