Monty  Boehm

Monty Boehm

1684856942

Jotai: Primitive and flexible state management for React

Jotai scales from a simple useState replacement to an enterprise TypeScript application.

  • Minimal core API (2kb)
  • Many utilities and integrations
  • No string keys (compared to Recoil)

Examples: Demo 1 | Demo 2

First, create a primitive atom

An atom represents a piece of state. All you need is to specify an initial value, which can be primitive values like strings and numbers, objects, and arrays. You can create as many primitive atoms as you want.

import { atom } from 'jotai'

const countAtom = atom(0)
const countryAtom = atom('Japan')
const citiesAtom = atom(['Tokyo', 'Kyoto', 'Osaka'])
const mangaAtom = atom({ 'Dragon Ball': 1984, 'One Piece': 1997, Naruto: 1999 })

Use the atom in your components

It can be used like React.useState:

import { useAtom } from 'jotai'

function Counter() {
  const [count, setCount] = useAtom(countAtom)
  return (
    <h1>
      {count}
      <button onClick={() => setCount((c) => c + 1)}>one up</button>
      ...

Create derived atoms with computed values

A new read-only atom can be created from existing atoms by passing a read function as the first argument. get allows you to fetch the contextual value of any atom.

const doubledCountAtom = atom((get) => get(countAtom) * 2)

function DoubleCounter() {
  const [doubledCount] = useAtom(doubledCountAtom)
  return <h2>{doubledCount}</h2>
}

Creating an atom from multiple atoms

You can combine multiple atoms to create a derived atom.

const count1 = atom(1)
const count2 = atom(2)
const count3 = atom(3)

const sum = atom((get) => get(count1) + get(count2) + get(count3))

Or if you like fp patterns ...

const atoms = [count1, count2, count3, ...otherAtoms]
const sum = atom((get) => atoms.map(get).reduce((acc, count) => acc + count))

Derived async atoms needs suspense

You can make the read function an async function too.

const urlAtom = atom('https://json.host.com')
const fetchUrlAtom = atom(async (get) => {
  const response = await fetch(get(urlAtom))
  return await response.json()
})

function Status() {
  // Re-renders the component after urlAtom is changed and the async function above concludes
  const [json] = useAtom(fetchUrlAtom)
  ...

You can create a writable derived atom

Specify a write function at the second argument. get will return the current value of an atom. set will update the value of an atom.

const decrementCountAtom = atom(
  (get) => get(countAtom),
  (get, set, _arg) => set(countAtom, get(countAtom) - 1)
)

function Counter() {
  const [count, decrement] = useAtom(decrementCountAtom)
  return (
    <h1>
      {count}
      <button onClick={decrement}>Decrease</button>
      ...

Write only atoms

Just do not define a read function.

const multiplyCountAtom = atom(null, (get, set, by) =>
  set(countAtom, get(countAtom) * by)
)

function Controls() {
  const [, multiply] = useAtom(multiplyCountAtom)
  return <button onClick={() => multiply(3)}>triple</button>
}

Async actions

Just make the write function an async function and call set when you're ready.

const fetchCountAtom = atom(
  (get) => get(countAtom),
  async (_get, set, url) => {
    const response = await fetch(url)
    set(countAtom, (await response.json()).count)
  }
)

function Controls() {
  const [count, compute] = useAtom(fetchCountAtom)
  return (
    <button onClick={() => compute('http://count.host.com')}>compute</button>
    ...

Links


visit jotai.org or npm i jotai


Download Details:

Author: pmndrs
Source Code: https://github.com/pmndrs/jotai 
License: MIT license

#react #management #state #hacktoberfest 

Jotai: Primitive and flexible state management for React

A Flutter Plugin to Prevent App into App Nap State

flutter_prevent_nap

A Flutter plugin to prevent app into app nap state.

Usage

final preventNap = FlutterPreventNap();
final key = await preventNap.beginActivity("");

// do something important

preventNap.endActivity(key); 

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add flutter_prevent_nap

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  flutter_prevent_nap: ^0.0.3

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:flutter_prevent_nap/flutter_prevent_nap.dart'; 

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_prevent_nap/flutter_prevent_nap.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Center(
          child: ElevatedButton(
            onPressed: () async {
              final preventNap = FlutterPreventNap();
              final key = await preventNap.beginActivity("");

              // do something important

              preventNap.endActivity(key);
            },
            child: const Text("Execute an important task!"),
          ),
        ),
      ),
    );
  }
} 

Download Details:

Author: farmer00317558

Source Code: https://github.com/farmer00317558/flutter_prevent_nap

#flutter #state 

A Flutter Plugin to Prevent App into App Nap State

Flutter Package Which Simplifies Flows with Flexible, Declarative API

Usage

Define a Flow State

The flow state will be the state which drives the flow. Each time this state changes, a new navigation stack will be generated based on the new flow state.

class Profile {
  const Profile({this.name, this.age, this.weight});

  final String? name;
  final int? age;
  final int? weight;

  Profile copyWith({String? name, int? age, int? weight}) {
    return Profile(
      name: name ?? this.name,
      age: age ?? this.age,
      weight: weight ?? this.weight,
    );
  }
}

Create a FlowBuilder

FlowBuilder is a widget which builds a navigation stack in response to changes in the flow state. onGeneratePages will be invoked for each state change and must return the new navigation stack as a list of pages.

FlowBuilder<Profile>(
  state: const Profile(),
  onGeneratePages: (profile, pages) {
    return [
      MaterialPage(child: NameForm()),
      if (profile.name != null) MaterialPage(child: AgeForm()),
    ];
  },
);

Update the Flow State

The state of the flow can be updated via context.flow<T>().update.

class NameForm extends StatefulWidget {
  @override
  _NameFormState createState() => _NameFormState();
}

class _NameFormState extends State<NameForm> {
  var _name = '';

  void _continuePressed() {
    context.flow<Profile>().update((profile) => profile.copyWith(name: _name));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Name')),
      body: Center(
        child: Column(
          children: <Widget>[
            TextField(
              onChanged: (value) => setState(() => _name = value),
              decoration: InputDecoration(
                labelText: 'Name',
                hintText: 'John Doe',
              ),
            ),
            RaisedButton(
              child: const Text('Continue'),
              onPressed: _name.isNotEmpty ? _continuePressed : null,
            )
          ],
        ),
      ),
    );
  }
}

Complete the Flow

The flow can be completed via context.flow<T>().complete.

class AgeForm extends StatefulWidget {
  @override
  _AgeFormState createState() => _AgeFormState();
}

class _AgeFormState extends State<AgeForm> {
  int? _age;

  void _continuePressed() {
    context
        .flow<Profile>()
        .complete((profile) => profile.copyWith(age: _age));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Age')),
      body: Center(
        child: Column(
          children: <Widget>[
            TextField(
              onChanged: (value) => setState(() => _age = int.parse(value)),
              decoration: InputDecoration(
                labelText: 'Age',
                hintText: '42',
              ),
              keyboardType: TextInputType.number,
            ),
            RaisedButton(
              child: const Text('Continue'),
              onPressed: _age != null ? _continuePressed : null,
            )
          ],
        ),
      ),
    );
  }
}

FlowController

A FlowBuilder can also be created with a custom FlowController in cases where the flow can be manipulated outside of the sub-tree.

class MyFlow extends StatefulWidget {
  @override
  State<MyFlow> createState() => _MyFlowState();
}

class _MyFlowState extends State<MyFlow> {
  late FlowController<Profile> _controller;

  @override
  void initState() {
    super.initState();
    _controller = FlowController(const Profile());
  }

  @override
  Widget build(BuildContext context) {
    return FlowBuilder(
      controller: _controller,
      onGeneratePages: ...,
    );
  }

  @override dispose() {
    _controller.dispose();
    super.dispose();
  }
}

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add flow_builder

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  flow_builder: ^0.0.9

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:flow_builder/flow_builder.dart';

example/lib/main.dart

import 'package:example/authentication_flow/authentication_flow.dart';
import 'package:example/location_flow/location_flow.dart';
import 'package:example/onboarding_flow/onboarding_flow.dart';
import 'package:example/profile_flow/profile_flow.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

void main() => runApp(MyApp(locationRepository: LocationRepository()));

class MyApp extends StatelessWidget {
  MyApp({required LocationRepository locationRepository})
      : _locationRepository = locationRepository;

  final LocationRepository _locationRepository;

  @override
  Widget build(BuildContext context) {
    return RepositoryProvider.value(
      value: _locationRepository,
      child: MaterialApp(home: Home()),
    );
  }
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Home')),
      body: Builder(
        builder: (context) {
          return ListView(
            children: [
              ListTile(
                leading: const Icon(Icons.help_outline),
                title: const Text('Onboarding Flow'),
                trailing: const Icon(Icons.chevron_right),
                onTap: () async {
                  await Navigator.of(context).push(OnboardingFlow.route());
                  ScaffoldMessenger.of(context)
                    ..hideCurrentSnackBar()
                    ..showSnackBar(
                      const SnackBar(
                        content: Text('Onboarding Flow Complete!'),
                      ),
                    );
                },
              ),
              ListTile(
                leading: const Icon(Icons.person_outline),
                title: const Text('Profile Flow'),
                trailing: const Icon(Icons.chevron_right),
                onTap: () async {
                  final profile = await Navigator.of(context).push(
                    ProfileFlow.route(),
                  );
                  ScaffoldMessenger.of(context)
                    ..hideCurrentSnackBar()
                    ..showSnackBar(
                      SnackBar(
                        content: Text('Profile Flow Complete!\n$profile'),
                      ),
                    );
                },
              ),
              ListTile(
                leading: const Icon(Icons.location_city),
                title: const Text('Location Flow'),
                trailing: const Icon(Icons.chevron_right),
                onTap: () async {
                  final location = await Navigator.of(context).push(
                    LocationFlow.route(),
                  );
                  ScaffoldMessenger.of(context)
                    ..hideCurrentSnackBar()
                    ..showSnackBar(
                      SnackBar(
                        content: Text('Location Flow Complete!\n$location'),
                      ),
                    );
                },
              ),
              ListTile(
                leading: const Icon(Icons.security_rounded),
                title: const Text('Authentication Flow'),
                trailing: const Icon(Icons.chevron_right),
                onTap: () async {
                  await Navigator.of(context).push<AuthenticationState>(
                    AuthenticationFlow.route(),
                  );
                  ScaffoldMessenger.of(context)
                    ..hideCurrentSnackBar()
                    ..showSnackBar(
                      const SnackBar(
                        content: Text('Authentication Flow Complete!'),
                      ),
                    );
                },
              ),
            ],
          );
        },
      ),
    );
  }
}

Download Details:

Author: felangel.dev

Source Code: https://github.com/felangel/flow_builder

#flutter #flow #builder #state #api 

Flutter Package Which Simplifies Flows with Flexible, Declarative API
Oral  Brekke

Oral Brekke

1681913589

Auto populate Dropdown using jQuery AJAX in CakePHP 4

Dynamic-dependent dropdowns are very helpful to restrict user selection. You may have already seen this on the registration or profile page of the website where you need to select country, state, and city. Options in the dropdown update every time when a country or state dropdown selection gets changed.

If your tables are properly interlinked in the database and want to list their data on the dropdown then you can make them dynamically dependent on one another and load their data using AJAX.

In this tutorial, I show how you can auto populate dropdown using jQuery AJAX with MySQL database data in CakePHP 4.

1. Create Table

In the example, I am using 3 tables –

  • countries
  • states
  • cities

countries (Store countries name) –

CREATE TABLE `countries` (
    `id` int(10) UNSIGNED NOT NULL,
    `name` varchar(80) NOT NULL
);

ALTER TABLE `countries`
    ADD PRIMARY KEY (`id`);

ALTER TABLE `countries`
    MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;

states (Store country states names) –

Added foreign key on country_id field.

CREATE TABLE `states` (
    `id` int(10) UNSIGNED NOT NULL,
    `country_id` int(10) UNSIGNED NOT NULL,
    `name` varchar(80) NOT NULL
);

ALTER TABLE `states`
    ADD PRIMARY KEY (`id`),
    ADD KEY `states_country_id_foreign` (`country_id`);

ALTER TABLE `states`
    MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;

cities (Store state cities name) –

Added foreign key on state_id field.

CREATE TABLE `cities` (
    `id` int(10) UNSIGNED NOT NULL,
    `state_id` int(10) UNSIGNED NOT NULL,
    `name` varchar(80) NOT NULL
);

ALTER TABLE `cities`
    ADD PRIMARY KEY (`id`),
    ADD KEY `cities_state_id_foreign` (`state_id`);

ALTER TABLE `cities`
    MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;

2. Database Configuration

  • Open config/app_local.php file.
  • Specify your database configuration details in the Datasources default.
'Datasources' => [
     'default' => [
          'host' => '127.0.0.1',
          /*
          * CakePHP will use the default DB port based on the driver selected
          * MySQL on MAMP uses port 8889, MAMP users will want to uncomment
          * the following line and set the port accordingly
          */
          //'port' => 'non_standard_port_number',

          'username' => 'root',
          'password' => 'root',

          'database' => 'cakephp4',
          /*
          * If not using the default 'public' schema with the PostgreSQL driver
          * set it here.
          */
          //'schema' => 'myapp',

          /*
          * You can use a DSN string to set the entire configuration
          */
          'url' => env('DATABASE_URL', null),
     ],

     /*
     * The test connection is used during the test suite.
     */
     'test' => [
          'host' => 'localhost',
          //'port' => 'non_standard_port_number',
          'username' => 'my_app',
          'password' => 'secret',
          'database' => 'test_myapp',
          //'schema' => 'myapp',
          'url' => env('DATABASE_TEST_URL', 'sqlite://127.0.0.1/tests.sqlite'),
     ],
],

3. Create Model

Create 3 models –

  • Countries
  • States
  • Cities

Countries Model –

bin/cake bake model Countries

This will create 2 files  –

  • src/Model/Entity/Country.php
<?php
declare(strict_types=1);

namespace App\Model\Entity;

use Cake\ORM\Entity;

class Country extends Entity
{
     protected $_accessible = [ 
         'name' => true,
         'states' => true,
     ];
}
  • src/Model/Table/CountriesTable.php
<?php
declare(strict_types=1);

namespace App\Model\Table;

use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;

class CountriesTable extends Table
{
     public function initialize(array $config): void
     {
           parent::initialize($config);

           $this->setTable('countries');
           $this->setDisplayField('name');
           $this->setPrimaryKey('id');

           $this->hasMany('States', [
               'foreignKey' => 'country_id',
           ]);
     }

     public function validationDefault(Validator $validator): Validator
     {
           $validator
               ->scalar('name')
               ->maxLength('name', 255)
               ->requirePresence('name', 'create')
               ->notEmptyString('name');

           return $validator;
     }
}

States Model –

bin/cake bake model States

This will create 2 files –

  • src/Model/Entity/State.php
<?php
declare(strict_types=1);

namespace App\Model\Entity;

use Cake\ORM\Entity;

class State extends Entity
{
     protected $_accessible = [
         'country_id' => true,
         'name' => true,
         'country' => true,
         'cities' => true,
     ];
}
  • src/Model/Table/StatesTable.php
<?php
declare(strict_types=1);

namespace App\Model\Table;

use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;

class StatesTable extends Table
{

     public function initialize(array $config): void
     {
           parent::initialize($config);

           $this->setTable('states');
           $this->setDisplayField('name');
           $this->setPrimaryKey('id');

           $this->belongsTo('Countries', [
               'foreignKey' => 'country_id',
               'joinType' => 'INNER',
           ]);
           $this->hasMany('Cities', [
               'foreignKey' => 'state_id',
           ]);
     }

     public function validationDefault(Validator $validator): Validator
     {
           $validator
               ->notEmptyString('country_id');

           $validator
               ->scalar('name')
               ->maxLength('name', 255)
               ->requirePresence('name', 'create')
               ->notEmptyString('name');

           return $validator;
     }

     public function buildRules(RulesChecker $rules): RulesChecker
     {
           $rules->add($rules->existsIn('country_id', 'Countries'), ['errorField' => 'country_id']);

           return $rules;
     }
}

Cities Model –

This will create 2 files –

  • src/Model/Entity/City.php
<?php
declare(strict_types=1);

namespace App\Model\Entity;

use Cake\ORM\Entity;

class City extends Entity
{
     protected $_accessible = [
         'state_id' => true,
         'name' => true,
         'state' => true,
     ];
}
  • src/Model/Table/CitiesTable.php
<?php
declare(strict_types=1);

namespace App\Model\Table;

use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;

class CitiesTable extends Table
{

     public function initialize(array $config): void
     {
          parent::initialize($config);

          $this->setTable('cities');
          $this->setDisplayField('name');
          $this->setPrimaryKey('id');

          $this->belongsTo('States', [
              'foreignKey' => 'state_id',
              'joinType' => 'INNER',
          ]);
     }

     public function validationDefault(Validator $validator): Validator
     {
          $validator
              ->notEmptyString('state_id');

          $validator
              ->scalar('name')
              ->maxLength('name', 255)
              ->requirePresence('name', 'create')
              ->notEmptyString('name');

          return $validator;
     }

     public function buildRules(RulesChecker $rules): RulesChecker
     {
          $rules->add($rules->existsIn('state_id', 'States'), ['errorField' => 'state_id']);

          return $rules;
     }
}

4. Create Controller

  • Create a AutopopulateController.php file in src/Controller/ folder.
  • Create AutopopulateController Class that extends AppController.

Create 3 method –

  • index() – Fetch all records from the countries table. Loop on the fetched records and store them in $country_arr Array. Using $this->set() pass $country_arr Array to template.
  • getCountryStates() – Using this method return states list of the requested country from AJAX request.

Read POST country_id and assign it to the variable. Fetch all records from the states table where country_id = $country_id.

Loop on the fetch records and store state id and name in $data_arr Array. Return $data_arr Array in JSON format.

  • getStateCities() – Using this method return cities list of the requested state from AJAX request.

Read POST state_id and assign it to the variable. Fetch all records from the cities table where state_id = $state_id.

Loop on the fetch records and store city id and name in $data_arr Array. Return $data_arr Array in JSON format.

Completed Code

<?php
declare(strict_types=1);

namespace App\Controller;

class AutopopulateController extends AppController
{

     public function index(){

          ## Fetch all countries
          $countries = $this->getTableLocator()->get('Countries');
          $query = $countries->find('all')->order(['name' => 'ASC']);
          $countriesList = $query->toArray();

          $country_arr = array(); 
          foreach($countriesList as $country){
               $country_arr[$country['id']] = $country['name'];
          }

          $this->set(compact('country_arr'));
     }

     // Get country states
     public function getCountryStates(){

          // POST value
          $country_id = $this->request->getData()['country_id'];

          ## Fetch all states of country_id
          $states = $this->getTableLocator()->get('States');
          $query = $states->find('all')
               ->where(['country_id' => $country_id])
               ->order(['name' => 'ASC']);
          $statesList = $query->toArray();

          $data_arr = array();
          foreach($statesList as $state){
               $data_arr[] = array(
                   'id' => $state['id'],
                   'name' => $state['name']
               );
          }

          echo json_encode($data_arr);
          die;
     }

     // Get state cities
     public function getStateCities(){

          // POST value
          $state_id = $this->request->getData()['state_id'];

          ## Fetch all cities of state_id
          $cities = $this->getTableLocator()->get('Cities');
          $query = $cities->find('all')
              ->where(['state_id' => $state_id])
              ->order(['name' => 'ASC']);
          $citiesList = $query->toArray();

          $data_arr = array();
          foreach($citiesList as $city){
               $data_arr[] = array(
                   'id' => $city['id'],
                   'name' => $city['name']
               );
          }

          echo json_encode($data_arr);
          die;
     }

}

6. Include jQuery and CSRF token

I am including jQuery and CSRF token on templates/layout/default.php file.

Stored CSRF token in <meta > tag –

<?= $this->Html->meta('csrfToken', $this->request->getAttribute('csrfToken')); ?>

and jQuery in <head > section –

<?= $this->Html->script('https://code.jquery.com/jquery.min.js'); ?>

Completed Code

<?php
$cakeDescription = 'CakePHP: the rapid development php framework';
?>
<!DOCTYPE html>
<html>
<head>
     <?= $this->Html->charset() ?>
     <meta name="viewport" content="width=device-width, initial-scale=1">

     <!-- CSRF Token -->
     <?= $this->Html->meta('csrfToken', $this->request->getAttribute('csrfToken')); ?>
     <title>
           <?= $cakeDescription ?>:
           <?= $this->fetch('title') ?>
     </title>
     <?= $this->Html->meta('icon') ?>

     <link href="https://fonts.googleapis.com/css?family=Raleway:400,700" rel="stylesheet">

     <?= $this->Html->css(['normalize.min', 'milligram.min', 'cake']) ?>

     <!-- jQuery -->
     <?= $this->Html->script('https://code.jquery.com/jquery.min.js'); ?>

     <?= $this->fetch('meta') ?>
     <?= $this->fetch('css') ?>
     <?= $this->fetch('script') ?>
</head>
<body>
     <nav class="top-nav">
          <div class="top-nav-title">
               <a href="<?= $this->Url->build('/') ?>"><span>Cake</span>PHP</a>
          </div>
          <div class="top-nav-links">
               <a target="_blank" rel="noopener" href="https://book.cakephp.org/4/">Documentation</a>
               <a target="_blank" rel="noopener" href="https://api.cakephp.org/">API</a>
          </div>
     </nav>
     <main class="main">
          <div class="container">
               <?= $this->Flash->render() ?>
               <?= $this->fetch('content') ?>
          </div>
     </main>
     <footer>
     </footer>
</body>
</html>

6. Create Template

Create Autopopulate folder in templates/ location. In the Autopopulate folder create index.php file – templates/Autopopulate/index.php.

Create 3 <select > elements –

  • country – Display the passed country list from the controller.
  • state – Empty dropdown. Data load using jQuery AJAX when a country is been selected.
  • city – Empty dropdown. Data load using jQuery AJAX when a state is been selected.

jQuery

Read CSRF token from the <meta > tag and assign it to csrfToken variable.

Country Change –

Define change event on #country_id. Read selected country_id and empty the state and city dropdown. If country_id is not empty then send AJAX POST request to <?= $this->Url->build(['controller' => 'Autopopulate','action' => 'getCountryStates']) ?>.

Here, pass country_id – {country_id: country_id} as data, set dataType: 'json', pass CSRF token using header.

On successful callback loop on the response and add a new <option > in state dropdown.

State Change –

Define change event on #state_id. Read selected state_id and empty the city dropdown. If state_id is not empty then send AJAX POST request to <?= $this->Url->build(['controller' => 'Autopopulate','action' => 'getStateCities']) ?>.

Here, pass state_id – {state_id: state_id} as data, set dataType: 'json', pass CSRF token using header.

On successful callback loop on the response to add <option > in city dropdown.

Completed Code

<div class="row">
     <div class="col-6">

         <!-- Country -->
         <div id="input">
              <label for='country_id'>Country</label>
              <?php 
              echo $this->Form->select(
                  'country_id',
                  $country_arr,
                  [
                      'id' => 'country_id',
                      'empty' => '-- Select Country --'
                  ]
              );
              ?>
         </div>

         <!-- State -->
         <div id="input">
              <label for='state_id'>State</label>
              <?php 
              echo $this->Form->select(
                  'state_id',
                  [],
                  [
                      'id' => 'state_id',
                      'empty' => '-- Select State --'
                  ]
              );
              ?>
         </div>

         <!-- City -->
         <div id="input">
              <label for='city_id'>City</label>
              <?php 
              echo $this->Form->select(
                  'city_id',
                  [],
                  [
                      'id' => 'city_id',
                      'empty' => '-- Select City --'
                  ]
              );
              ?>
         </div>

     </div>
</div>
<!-- Script -->
<script type="text/javascript">
// Read CSRF Token
var csrfToken = $('meta[name="csrfToken"]').attr('content');
$(document).ready(function(){

     // Country change
     $('#country_id').change(function(){
          var country_id = $('#country_id').val();

          // Empty state and city dropdown
          $('#state_id').find('option').not(':first').remove();
          $('#city_id').find('option').not(':first').remove();

          if(country_id != ''){

               // AJAX request
               $.ajax({
                   url: "<?= $this->Url->build(['controller' => 'Autopopulate','action' => 'getCountryStates']) ?>",
                   type: 'post',
                   data: {country_id: country_id},
                   dataType: 'json',
                   headers:{
                        'X-CSRF-Token': csrfToken
                   },
                   success: function(response){

                        var len = response.length;

                        // Add response data to state dropdown
                        for( var i = 0; i<len; i++){
                             var id = response[i]['id'];
                             var name = response[i]['name'];

                             $("#state_id").append("<option value='"+id+"'>"+name+"</option>");

                        }
                   },
               });
          }

     });

     // State change
     $('#state_id').change(function(){
          var state_id = $('#state_id').val();

          // Empty city dropdown
          $('#city_id').find('option').not(':first').remove();

          if(state_id != ''){

               // AJAX request
               $.ajax({
                    url: "<?= $this->Url->build(['controller' => 'Autopopulate','action' => 'getStateCities']) ?>",
                    type: 'post',
                    data: {state_id: state_id},
                    dataType: 'json',
                    headers:{
                         'X-CSRF-Token': csrfToken
                    },
                    success: function(response){

                         var len = response.length;

                         // Add response data to city dropdown
                         for( var i = 0; i<len; i++){
                              var id = response[i]['id'];
                              var name = response[i]['name'];

                              $("#city_id").append("<option value='"+id+"'>"+name+"</option>");
                         }
                    },
               });
          }

     });

});
</script>

7. Output

View Output


8. Conclusion

In the example, I returned a JSON response from the server and looped on it to add a new item to the dropdown, but you can also return an HTML response and directly append it to the dropdown.

After implementing this on your project if data is not loading in the dropdown then debug it using the browser console and network tab.

You can also checkout this tutorial if you want to know jQuery UI autocomplete using jQuery AJAX in CakePHP 4.

Original article source at: https://makitweb.com/

#php #cakephp #jquery #ajax 

Auto populate Dropdown using jQuery AJAX in CakePHP 4

A Flutter Plugin to Handle Phone Call State and Execute

phone_state_background

A flutter plugin to handle Phone Call State and execute a Dart callback in background.
 

Warning

This plugin only supported in android platform.


 

IOS Implementation

Corrently IOS is not supported. Unfortunately I'm not familiar with IOS development neither with Switf/ObjC languages, so if you wish to help any PR will be welcome.


 

Android

Add the following permissions to your AndroidManifest.xml file:

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />

Also, apparently it is necessary to register the broadcast receiver manually, otherwise an error will be throw saying that our receiver does not exist inside the app:

<receiver android:name="me.sodipto.phone_state_background.PhoneStateBackgroundServiceReceiver"
    android:exported="false">
    <intent-filter>
        <action android:name="android.intent.action.PHONE_STATE" />
    </intent-filter>
</receiver>


 

Getting started

All you need to start using our package after installing it, is defining a callback which must be a top level function or static function, that will be called by our plugin when any incoming or outgoing call events are detected.

void phoneStateBackgroundCallbackHandler(PhoneStateBackgroundEvent event, String number, int duration)

This callback handler must accept 3 arguments:

phoneStateBackgroundEvent: The event type detect by our plugin in background.

number: The incoming/outgoin number that is triggering the phone state call.

duration: An integer that represents the duration of the call in seconds.

The PhoneStateBackgroundEvent is an enum with four possible values:

Event ValueDescription
incomingstartIndicates an incoming call.
incomingmissedIndicates an incoming call missed.
incomingreceivedIndicates an incoming call received.
incomingendIndicates an incoming call end.
outgoingstartIndicates an outgoing call start.
outgoingendIndicates an outgoing call end.

Since all this process happens in background in a Dart Isolate, there's no guarantee that the current OS will call the registered callback as soon as an event is triggered or that the callback will ever be called at all, each OS handle background services with different policies. Make sure to ask user permission before calling the PhoneStateBackground.initialize method of our plugin. Check the example to see a simple implementation of it.

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add phone_state_background

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  phone_state_background: ^0.0.2

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:phone_state_background/phone_state_background.dart'; 

example/lib/main.dart

import 'package:flutter/material.dart';
import 'dart:async';

import 'package:phone_state_background/phone_state_background.dart';

/// Defines a callback that will handle all background incoming events
Future<void> phoneStateBackgroundCallbackHandler(
  PhoneStateBackgroundEvent event,
  String number,
  int duration,
) async {
  switch (event) {
    case PhoneStateBackgroundEvent.incomingstart:
      print('Incoming call start, number: $number, duration: $duration s');
      break;
    case PhoneStateBackgroundEvent.incomingmissed:
      print('Incoming call missed, number: $number, duration: $duration s');
      break;
    case PhoneStateBackgroundEvent.incomingreceived:
      print('Incoming call received, number: $number, duration: $duration s');
      break;
    case PhoneStateBackgroundEvent.incomingend:
      print('Incoming call ended, number: $number, duration $duration s');
      break;
    case PhoneStateBackgroundEvent.outgoingstart:
      print('Ougoing call start, number: $number, duration: $duration s');
      break;
    case PhoneStateBackgroundEvent.outgoingend:
      print('Ougoing call ended, number: $number, duration: $duration s');
      break;
  }
}

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Phone State Background',
      theme: ThemeData(
        primarySwatch: Colors.blueGrey,
      ),
      home: const MyHomePage(title: 'Phone State Background'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool? hasPermission;

  @override
  void initState() {
    super.initState();
    _hasPermission();
  }

  Future<void> _hasPermission() async {
    final permission = await PhoneStateBackground.checkPermission();
    print('Permission $permission');
    setState(() => hasPermission = permission);
  }

  Future<void> _requestPermission() async {
    await PhoneStateBackground.requestPermissions();
    await _hasPermission();
  }

  Future<void> _stop() async {
    await PhoneStateBackground.stopPhoneStateBackground();
  }

  Future<void> _init() async {
    if (hasPermission != true) return;
    await PhoneStateBackground.initialize(phoneStateBackgroundCallbackHandler);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Has Permission: $hasPermission',
              style: TextStyle(
                  fontSize: 16,
                  color: hasPermission! ? Colors.green : Colors.red),
            ),
            const SizedBox(
              height: 20,
            ),
            SizedBox(
              width: 180,
              child: ElevatedButton(
                onPressed: () => _requestPermission(),
                child: const Text('Check Permission'),
              ),
            ),
            Padding(
              padding: const EdgeInsets.symmetric(vertical: 20),
              child: SizedBox(
                width: 180,
                child: ElevatedButton(
                  onPressed: () => _init(),
                  style: ElevatedButton.styleFrom(
                    primary: Colors.green, // Background color
                  ),
                  child: const Text('Start Listener'),
                ),
              ),
            ),
            SizedBox(
              width: 180,
              child: ElevatedButton(
                onPressed: () => _stop(),
                style: ElevatedButton.styleFrom(
                  primary: Colors.red, // Background color
                ),
                child: const Text('Stop Listener'),
              ),
            ),
          ],
        ),
      ),
    );
  }
} 

Download Details:

Author: sodipto

Source Code: https://github.com/sodipto/flutter-phone-state-background

#flutter #state #background 

A Flutter Plugin to Handle Phone Call State and Execute
Lawson  Wehner

Lawson Wehner

1679462221

BlockSuite: The Open-source Collaborative Editor Project Behind AFFiNE

BlockSuite


BlockSuite (pronounced "block sweet") is the open-source editor project behind AFFiNE. It provides an out-of-the-box block-based editor built on top of a framework designed for general-purpose collaborative applications. This monorepo maintains both the editor and the underlying framework.

⚠️ This project is under heavy development and is in a stage of rapid evolution. Stay tuned or see our roadmap here!

Introduction

BlockSuite works very differently than traditional rich text frameworks:

  • For the data model, BlockSuite eliminates the need to work with data-driven DSLs (e.g., operations, actions, commands, transforms). Instead, it utilizes CRDT as the single source of truth, offering a strongly-typed block tree model built on Yjs. With BlockSuite, manipulating blocks becomes as simple as updating a todo list. Moreover, by fully harnessing the power of CRDT, it supports zero-cost time travel, real-time collaboration, and out-of-the-box pluggable persistence backends.
  • For rich text editing, BlockSuite seamlessly organizes rich text content into discrete blocks. In BlockSuite, a document with 100 paragraphs can be rendered into 100 text blocks or 100 individual rich text editor instances, effectively eliminating the outdated practice of consolidating all content into a single, risky contenteditable monolith.
  • At the rendering layer, BlockSuite remains framework agnostic. It doesn't limit the block tree rendering to the DOM. Not only does it implement its entire document editing UI using Web Components, but it also offers a hybrid canvas-based renderer for whiteboard content sections. Both renderers can coexist on the same page and share a unified centralized data store.

BlockSuite is not intended to be yet another plugin-based rich text editing framework. Instead, it encourages building various collaborative applications directly through whatever UI framework you're comfortable with. To this end, we will try to open-source more foundational modules as reusable packages for this in the BlockSuite project.

Although BlockSuite is still in its early stages, you can already use the @blocksuite/editor package, the collaborative editor used in AFFiNE Alpha. Note that this editor is also a web component and is completely framework-independent!

Resources

Getting Started

The @blocksuite/editor package contains the editor built into AFFiNE. Its nightly versions are released daily based on the master branch, and they are always tested on CI. This means that the nightly versions can already be used in real-world projects like AFFiNE at any time:

pnpm i @blocksuite/editor@nightly

If you want to easily reuse most of the rich-text editing features, you can use the SimpleAffineEditor web component directly (code example here):

import { SimpleAffineEditor } from '@blocksuite/editor';
import '@blocksuite/editor/themes/affine.css';

const editor = new SimpleAffineEditor();
document.body.appendChild(editor);

Or equivalently, you can also use the declarative style:

<body>
  <simple-affine-editor></simple-affine-editor>
  <script type="module">
    import '@blocksuite/editor';
    import '@blocksuite/editor/themes/affine.css';
  </script>
</body>

👉 Try SimpleAffineEditor online

However, the SimpleAffineEditor here is just a thin wrapper with dozens of lines that doesn't enable the opt-in collaboration and data persistence features. If you are going to support more complicated real-world use cases (e.g., with customized block models and configured data sources), this will involve the use of these three following core packages:

  • The packages/store package is a data store built for general-purpose state management.
  • The packages/blocks package holds the default BlockSuite editable blocks.
  • The packages/editor package ships a complete BlockSuite-based editor.
pnpm i \
  @blocksuite/store@nightly \
  @blocksuite/blocks@nightly \
  @blocksuite/editor@nightly

And here is a minimal collaboration-ready editor showing how these underlying BlockSuite packages are composed together:

🚧 Here we will work with the concepts of Workspace, Page, Block and Slot. These are the primitives for building a block-based collaborative application. We are preparing a comprehensive documentation about their usage!

import '@blocksuite/blocks';
import { Workspace, Page } from '@blocksuite/store';
import { AffineSchemas } from '@blocksuite/blocks/models';
import { EditorContainer } from '@blocksuite/editor';

function main() {
  // Create a workspace with one default page
  const workspace = new Workspace({ id: 'test' }).register(AffineSchemas);
  const page = workspace.createPage('page0');

  // Create default blocks in the page
  const pageBlockId = page.addBlock('affine:page');
  const frameId = page.addBlock('affine:frame', {}, pageBlockId);
  page.addBlock('affine:paragraph', {}, frameId);

  // Init editor with the page store
  const editor = new EditorContainer();
  editor.page = page;
  document.body.appendChild(editor);
}

main();

For React developers, check out the @blocksuite/react doc for React components and hooks support.

Current Status (@blocksuite/editor)

For more detailed planning and progress, please checkout our GitHub project.

  • Basic text editing
    • ✅ Paragraph with inline style
    • ✅ Nested list
    • ✅ Code block
    • ✅ Markdown shortcuts
  • Block-level editing
    • ✅ Inline text format bar
    • ✅ Inline slash menu
    • ✅ Block hub
    • ✅ Block drag handle
    • ✅ Block-level selection
  • Rich-content
    • ✅ Image block
    • 🚧 Database block
    • 📌 Third-party embedded block
  • Whiteboard (edgeless mode)
    • ✅ Zooming and panning
    • ✅ Frame block
    • ⚛️ Shape element
    • ⚛️ Handwriting element
    • 🚧 Grouping
  • Playground
    • ✅ Multiplayer collaboration
    • ✅ Local data persistence
    • ✅ E2E test suite
  • Developer experience
    • ✅ Block tree update API
    • ✅ Zero cost time travel (undo/redo)
    • ✅ Reusable NPM package
    • ✅ React hooks integration
    • 📌 Dynamic block registration

Icons above correspond to the following meanings:

  • ✅ - Beta
  • ⚛️ - Alpha
  • 🚧 - Developing
  • 📌 - Planned

Building

See BUILDING.md for instructions on how to build BlockSuite from source code.

Contributing

BlockSuite accepts pull requests on GitHub. Before you start contributing, please make sure you have read and accepted our Contributor License Agreement. To indicate your agreement, simply edit this file and submit a pull request.


Download Details:

Author: toeverything
Source Code: https://github.com/toeverything/blocksuite 
License: MPL-2.0 license

#react #editor #components #block #state #management #webcomponents 

BlockSuite: The Open-source Collaborative Editor Project Behind AFFiNE
Gordon  Murray

Gordon Murray

1679182500

200 Bytes to Never Think About React State Management Libraries Ever

Unstated Next

200 bytes to never think about React state management libraries ever again

  • React Hooks use them for all your state management.
  • ~200 bytes min+gz.
  • Familiar API just use React as intended.
  • Minimal API it takes 5 minutes to learn.
  • Written in TypeScript and will make it easier for you to type your React code.

But, the most important question: Is this better than Redux? Well...

  • It's smaller. It's 40x smaller.
  • It's faster. Componentize the problem of performance.
  • It's easier to learn. You already will have to know React Hooks & Context, just use them, they rock.
  • It's easier to integrate. Integrate one component at a time, and easily integrate with every React library.
  • It's easier to test. Testing reducers is a waste of your time, make it easier to test your React components.
  • It's easier to typecheck. Designed to make most of your types inferable.
  • It's minimal. It's just React.

So you decide.

See Migration From Unstated docs →

Install

npm install --save unstated-next

Example

import React, { useState } from "react"
import { createContainer } from "unstated-next"
import { render } from "react-dom"

function useCounter(initialState = 0) {
  let [count, setCount] = useState(initialState)
  let decrement = () => setCount(count - 1)
  let increment = () => setCount(count + 1)
  return { count, decrement, increment }
}

let Counter = createContainer(useCounter)

function CounterDisplay() {
  let counter = Counter.useContainer()
  return (
    <div>
      <button onClick={counter.decrement}>-</button>
      <span>{counter.count}</span>
      <button onClick={counter.increment}>+</button>
    </div>
  )
}

function App() {
  return (
    <Counter.Provider>
      <CounterDisplay />
      <Counter.Provider initialState={2}>
        <div>
          <div>
            <CounterDisplay />
          </div>
        </div>
      </Counter.Provider>
    </Counter.Provider>
  )
}

render(<App />, document.getElementById("root"))

API

createContainer(useHook)

import { createContainer } from "unstated-next"

function useCustomHook() {
  let [value, setValue] = useState()
  let onChange = e => setValue(e.currentTarget.value)
  return { value, onChange }
}

let Container = createContainer(useCustomHook)
// Container === { Provider, useContainer }

<Container.Provider>

function ParentComponent() {
  return (
    <Container.Provider>
      <ChildComponent />
    </Container.Provider>
  )
}

<Container.Provider initialState>

function useCustomHook(initialState = "") {
  let [value, setValue] = useState(initialState)
  // ...
}

function ParentComponent() {
  return (
    <Container.Provider initialState={"value"}>
      <ChildComponent />
    </Container.Provider>
  )
}

Container.useContainer()

function ChildComponent() {
  let input = Container.useContainer()
  return <input value={input.value} onChange={input.onChange} />
}

useContainer(Container)

import { useContainer } from "unstated-next"

function ChildComponent() {
  let input = useContainer(Container)
  return <input value={input.value} onChange={input.onChange} />
}

Guide

If you've never used React Hooks before, I recommend pausing and going to read through the excellent docs on the React site.

So with hooks you might create a component like this:

function CounterDisplay() {
  let [count, setCount] = useState(0)
  let decrement = () => setCount(count - 1)
  let increment = () => setCount(count + 1)
  return (
    <div>
      <button onClick={decrement}>-</button>
      <p>You clicked {count} times</p>
      <button onClick={increment}>+</button>
    </div>
  )
}

Then if you want to share the logic behind the component, you could pull it out into a custom hook:

function useCounter() {
  let [count, setCount] = useState(0)
  let decrement = () => setCount(count - 1)
  let increment = () => setCount(count + 1)
  return { count, decrement, increment }
}

function CounterDisplay() {
  let counter = useCounter()
  return (
    <div>
      <button onClick={counter.decrement}>-</button>
      <p>You clicked {counter.count} times</p>
      <button onClick={counter.increment}>+</button>
    </div>
  )
}

But what if you want to share the state in addition to the logic, what do you do?

This is where context comes into play:

function useCounter() {
  let [count, setCount] = useState(0)
  let decrement = () => setCount(count - 1)
  let increment = () => setCount(count + 1)
  return { count, decrement, increment }
}

let Counter = createContext(null)

function CounterDisplay() {
  let counter = useContext(Counter)
  return (
    <div>
      <button onClick={counter.decrement}>-</button>
      <p>You clicked {counter.count} times</p>
      <button onClick={counter.increment}>+</button>
    </div>
  )
}

function App() {
  let counter = useCounter()
  return (
    <Counter.Provider value={counter}>
      <CounterDisplay />
      <CounterDisplay />
    </Counter.Provider>
  )
}

This is great, it's perfect, more people should write code like this.

But sometimes we all need a little bit more structure and intentional API design in order to get it consistently right.

By introducing the createContainer() function, you can think about your custom hooks as "containers" and have an API that's clear and prevents you from using it wrong.

import { createContainer } from "unstated-next"

function useCounter() {
  let [count, setCount] = useState(0)
  let decrement = () => setCount(count - 1)
  let increment = () => setCount(count + 1)
  return { count, decrement, increment }
}

let Counter = createContainer(useCounter)

function CounterDisplay() {
  let counter = Counter.useContainer()
  return (
    <div>
      <button onClick={counter.decrement}>-</button>
      <p>You clicked {counter.count} times</p>
      <button onClick={counter.increment}>+</button>
    </div>
  )
}

function App() {
  return (
    <Counter.Provider>
      <CounterDisplay />
      <CounterDisplay />
    </Counter.Provider>
  )
}

Here's the diff of that change:

- import { createContext, useContext } from "react"
+ import { createContainer } from "unstated-next"

  function useCounter() {
    ...
  }

- let Counter = createContext(null)
+ let Counter = createContainer(useCounter)

  function CounterDisplay() {
-   let counter = useContext(Counter)
+   let counter = Counter.useContainer()
    return (
      <div>
        ...
      </div>
    )
  }

  function App() {
-   let counter = useCounter()
    return (
-     <Counter.Provider value={counter}>
+     <Counter.Provider>
        <CounterDisplay />
        <CounterDisplay />
      </Counter.Provider>
    )
  }

If you're using TypeScript (which I encourage you to learn more about if you are not), this also has the benefit of making TypeScript's built-in inference work better. As long as your custom hook is typed, then everything else will just work.

Tips

Tip #1: Composing Containers

Because we're just working with custom React hooks, we can compose containers inside of other hooks.

function useCounter() {
  let [count, setCount] = useState(0)
  let decrement = () => setCount(count - 1)
  let increment = () => setCount(count + 1)
  return { count, decrement, increment, setCount }
}

let Counter = createContainer(useCounter)

function useResettableCounter() {
  let counter = Counter.useContainer()
  let reset = () => counter.setCount(0)
  return { ...counter, reset }
}

Tip #2: Keeping Containers Small

This can be useful for keeping your containers small and focused. Which can be important if you want to code split the logic in your containers: Just move them to their own hooks and keep just the state in containers.

function useCount() {
  return useState(0)
}

let Count = createContainer(useCount)

function useCounter() {
  let [count, setCount] = Count.useContainer()
  let decrement = () => setCount(count - 1)
  let increment = () => setCount(count + 1)
  let reset = () => setCount(0)
  return { count, decrement, increment, reset }
}

Tip #3: Optimizing components

There's no "optimizing" unstated-next to be done, all of the optimizations you might do would be standard React optimizations.

1) Optimizing expensive sub-trees by splitting the component apart

Before:

function CounterDisplay() {
  let counter = Counter.useContainer()
  return (
    <div>
      <button onClick={counter.decrement}>-</button>
      <p>You clicked {counter.count} times</p>
      <button onClick={counter.increment}>+</button>
      <div>
        <div>
          <div>
            <div>SUPER EXPENSIVE RENDERING STUFF</div>
          </div>
        </div>
      </div>
    </div>
  )
}

After:

function ExpensiveComponent() {
  return (
    <div>
      <div>
        <div>
          <div>SUPER EXPENSIVE RENDERING STUFF</div>
        </div>
      </div>
    </div>
  )
}

function CounterDisplay() {
  let counter = Counter.useContainer()
  return (
    <div>
      <button onClick={counter.decrement}>-</button>
      <p>You clicked {counter.count} times</p>
      <button onClick={counter.increment}>+</button>
      <ExpensiveComponent />
    </div>
  )
}

2) Optimizing expensive operations with useMemo()

Before:

function CounterDisplay(props) {
  let counter = Counter.useContainer()

  // Recalculating this every time `counter` changes is expensive
  let expensiveValue = expensiveComputation(props.input)

  return (
    <div>
      <button onClick={counter.decrement}>-</button>
      <p>You clicked {counter.count} times</p>
      <button onClick={counter.increment}>+</button>
    </div>
  )
}

After:

function CounterDisplay(props) {
  let counter = Counter.useContainer()

  // Only recalculate this value when its inputs have changed
  let expensiveValue = useMemo(() => {
    return expensiveComputation(props.input)
  }, [props.input])

  return (
    <div>
      <button onClick={counter.decrement}>-</button>
      <p>You clicked {counter.count} times</p>
      <button onClick={counter.increment}>+</button>
    </div>
  )
}

3) Reducing re-renders using React.memo() and useCallback()

Before:

function useCounter() {
  let [count, setCount] = useState(0)
  let decrement = () => setCount(count - 1)
  let increment = () => setCount(count + 1)
  return { count, decrement, increment }
}

let Counter = createContainer(useCounter)

function CounterDisplay(props) {
  let counter = Counter.useContainer()
  return (
    <div>
      <button onClick={counter.decrement}>-</button>
      <p>You clicked {counter.count} times</p>
      <button onClick={counter.increment}>+</button>
    </div>
  )
}

After:

function useCounter() {
  let [count, setCount] = useState(0)
  let decrement = useCallback(() => setCount(count - 1), [count])
  let increment = useCallback(() => setCount(count + 1), [count])
  return { count, decrement, increment }
}

let Counter = createContainer(useCounter)

let CounterDisplayInner = React.memo(props => {
  return (
    <div>
      <button onClick={props.decrement}>-</button>
      <p>You clicked {props.count} times</p>
      <button onClick={props.increment}>+</button>
    </div>
  )
})

function CounterDisplay(props) {
  let counter = Counter.useContainer()
  return <CounterDisplayInner {...counter} />
}

4) Wrapping your elements with useMemo()

via Dan Abramov

Before:

function CounterDisplay(props) {
  let counter = Counter.useContainer()
  let count = counter.count
  
  return (
    <p>You clicked {count} times</p>
  )
}

After:

function CounterDisplay(props) {
  let counter = Counter.useContainer()
  let count = counter.count
  
  return useMemo(() => (
    <p>You clicked {count} times</p>
  ), [count])
}

Relation to Unstated

I consider this library the spiritual successor to Unstated. I created Unstated because I believed that React was really great at state management already and the only missing piece was sharing state and logic easily. So I created Unstated to be the "minimal" solution to sharing React state and logic.

However, with Hooks, React has become much better at sharing state and logic. To the point that I think Unstated has become an unnecessary abstraction.

HOWEVER, I think many developers have struggled seeing how to share state and logic with React Hooks for "application state". That may just be an issue of documentation and community momentum, but I think that an API could help bridge that mental gap.

That API is what Unstated Next is. Instead of being the "Minimal API for sharing state and logic in React", it is now the "Minimal API for understanding shared state and logic in React".

I've always been on the side of React. I want React to win. I would like to see the community abandon state management libraries like Redux, and find better ways of making use of React's built-in toolchain.

If instead of using Unstated, you just want to use React itself, I would highly encourage that. Write blog posts about it! Give talks about it! Spread your knowledge in the community.

Migration from unstated

I've intentionally published this as a separate package name because it is a complete reset on the API. This way you can have both installed and migrate incrementally.

Please provide me with feedback on that migration process, because over the next few months I hope to take that feedback and do two things:

  • Make sure unstated-next fulfills all the needs of unstated users.
  • Make sure unstated has a clean migration process towards unstated-next.

I may choose to add APIs to either library to make life easier for developers. For unstated-next I promise that the added APIs will be as minimal as possible and I'll try to keep the library small.

In the future, I will likely merge unstated-next back into unstated as a new major version. unstated-next will still exist so that you can have both unstated@2 and unstated-next installed. Then when you are done with the migration, you can update to unstated@3 and remove unstated-next (being sure to update all your imports as you do... should be just a find-and-replace).

Even though this is a major new API change, I hope that I can make this migration as easy as possible on you. I'm optimizing for you to get to using the latest React Hooks APIs and not for preserving code written with Unstated.Container's. Feel free to provide feedback on how that could be done better.


English | 中文 | Русский | ภาษาไทย | Tiếng Việt
(Please contribute translations!)


Download Details:

Author: jamiebuilds
Source Code: https://github.com/jamiebuilds/unstated-next 
License: MIT license

#react #redux #library #state #management 

200 Bytes to Never Think About React State Management Libraries Ever

A Simple and Easy to Use State Manager for Flutter

Telescope
Just another state manager for flutter based on observable design pattern.

Telescope tries to be:

  1. Easy to learn (You can learn it in 5-10 min by reading README.md file).
  2. Easy to use (with dependsOn and saveOnDisk features).
  3. Flexible
    1. Can be used beside other state managers.
    2. It lets you do it in your way.
  4. Make it harder to make bugs
    1. With separation of concerns.
    2. No setState() needed.
  5. Performance (just rebuild widgets that need to rebuild).

How to use

In 3 easy steps.

1. Make a telescope :

  var textValue = Telescope("default value");

2. Watch(this):

Put this in middle of you widget build function.
You can watch single telescope in multiple widget

@override
Widget build(BuildContext context) {
  return Material(
      child: SafeArea(
          child: Container(
            child: Column(children: [
              // watch like this ('this' is State that will automatically rebuild on data change )
              Text(textValue.watch(this)), 
              Text(textValue.watch(this)),
              Text(textValue.watch(this).length.toString()),
            ],),
          )
      )
  );
}

3. Update value:

You can update telescope.value from anywhere from your code:

onTap: (){
  textValue.value += "a";
}

Boom:

And state will get update automatically without calling setState


 

Other features:

Depends on:

Telescopes can be depended on other telescopes

var height = Telescope(186);
var weight = Telescope(72);

var bmi = Telescope.dependsOn([height,weight], () {
  return weight.value / ((height.value/100) * (height.value/100));
});

var showingText  = Telescope.dependsOn([bmi], () {
  return "weight is ${weight.value} and height is ${height.value} so bmi will be ${bmi.value.toString().substring(0,5)}";
});

So when ever height or weight value get changes, the bmi will calculate itself because it depends on height and weight.
And showingText will calculate itself too, because it depends on bmi.

Save On Disk

You can save telescope data on disk easily like this:

static var height = Telescope.saveOnDiskForBuiltInType(187, "bmi_height_input");

So if user close the app and open it again it will load last value of telescope for You.
 

TelescopeList

Telescope implementation for list

  • can be dependent
  • can save on disk
var items = TelescopeList(["ab", "abb", "bc", "bcc" , "c"]);

Save non built in values on disk

You need to implement OnDiskSaveAbility for your object:
For example you have Human class:

class Human{
   int height;
   int weight;
   Human(this.height,this.weight);

   @override
   int get hashCode => height*weight;
}

Then you need to make other class like this for Human:

class HumanOnDiskAbility implements OnDiskSaveAbility<Human>{
   @override
   Human parseOnDiskString(String data) {
      var sp = data.split(":");
      return Human(int.parse(sp[0]), int.parse(sp[1]));
   }

   @override
   String toOnDiskString(Human instance) => "${instance.height}:${instance.weight}";
}

And pass instance of HumanOnDiskAbility to Telescope:

var human = Telescope.saveOnDiskForNonBuiltInType(
        Human(187, 72),
        "human_for_bmi",
        HumanOnDiskAbility()
);

Telescope will use 'parseOnDiskString' and 'toOnDiskString' to serialize and deserialize your object.

 

This method also can use in TelescopeList in same way.

Examples

Checkout telescope/examples

License GPL3

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add telescope

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  telescope: ^1.0.0

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:telescope/telescope.dart'; 

example/lib/main.dart

void main(){
  // every example has a main function. run them
} 

Download Details:

Author: ali77gh

Source Code: https://github.com/ali77gh/Telescope

#flutter #state 

A Simple and Easy to Use State Manager for Flutter
Lawrence  Lesch

Lawrence Lesch

1677131340

Simple Global State for React with Hooks API Without Context API

React-hooks-global-state

Simple global state for React with Hooks API without Context API

Introduction

This is a library to provide a global state with React Hooks. It has following characteristics.

  • Optimization for shallow state getter and setter.
    • The library cares the state object only one-level deep.
  • TypeScript type definitions
    • A creator function creates hooks with types inferred.
  • Redux middleware support to some extent
    • Some of libraries in Redux ecosystem can be used.

Install

npm install react-hooks-global-state

Usage

setState style

import React from 'react';
import { createGlobalState } from 'react-hooks-global-state';

const initialState = { count: 0 };
const { useGlobalState } = createGlobalState(initialState);

const Counter = () => {
  const [count, setCount] = useGlobalState('count');
  return (
    <div>
      <span>Counter: {count}</span>
      {/* update state by passing callback function */}
      <button onClick={() => setCount(v => v + 1)}>+1</button>
      {/* update state by passing new value */}
      <button onClick={() => setCount(count - 1)}>-1</button>
    </div>
  );
};

const App = () => (
  <>
    <Counter />
    <Counter />
  </>
);

reducer style

import React from 'react';
import { createStore } from 'react-hooks-global-state';

const reducer = (state, action) => {
  switch (action.type) {
    case 'increment': return { ...state, count: state.count + 1 };
    case 'decrement': return { ...state, count: state.count - 1 };
    default: return state;
  }
};
const initialState = { count: 0 };
const { dispatch, useStoreState } = createStore(reducer, initialState);

const Counter = () => {
  const value = useStoreState('count');
  return (
    <div>
      <span>Counter: {value}</span>
      <button onClick={() => dispatch({ type: 'increment' })}>+1</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-1</button>
    </div>
  );
};

const App = () => (
  <>
    <Counter />
    <Counter />
  </>
);

API

createGlobalState

Create a global state.

It returns a set of functions

  • useGlobalState: a custom hook works like React.useState
  • getGlobalState: a function to get a global state by key outside React
  • setGlobalState: a function to set a global state by key outside React
  • subscribe: a function that subscribes to state changes

Parameters

  • initialState State

Examples

import { createGlobalState } from 'react-hooks-global-state';

const { useGlobalState } = createGlobalState({ count: 0 });

const Component = () => {
  const [count, setCount] = useGlobalState('count');
  ...
};

createStore

Create a global store.

It returns a set of functions

  • useStoreState: a custom hook to read store state by key
  • getState: a function to get store state by key outside React
  • dispatch: a function to dispatch an action to store

A store works somewhat similarly to Redux, but not the same.

Parameters

  • reducer Reducer<State, Action>
  • initialState State (optional, default (reducer as any)(undefined,{type:undefined}))
  • enhancer any?

Examples

import { createStore } from 'react-hooks-global-state';

const initialState = { count: 0 };
const reducer = ...;

const store = createStore(reducer, initialState);
const { useStoreState, dispatch } = store;

const Component = () => {
  const count = useStoreState('count');
  ...
};

Returns Store<State, Action>

useGlobalState

useGlobalState created by createStore is deprecated.

Type: function (stateKey: StateKey): any

Meta

  • deprecated: useStoreState instead

Examples

The examples folder contains working examples. You can run one of them with

PORT=8080 npm run examples:01_minimal

and open http://localhost:8080 in your web browser.

You can also try them in codesandbox.io: 01 02 03 04 05 06 07 08 09 10 11 13

Blogs

Community Wiki

Download Details:

Author: Dai-shi
Source Code: https://github.com/dai-shi/react-hooks-global-state 
License: MIT license

#typescript #react #state #management 

Simple Global State for React with Hooks API Without Context API
Monty  Boehm

Monty Boehm

1676709612

How to Everything About React State Management

How to Everything About React State Management

Highlights for State Management in React

🟠 React State Management enables entrepreneurs to build an enterprise app that is scalable, maintainable, and performant.
🟠 There are different ways to effectively apply state management in React js applications: using component state, context API, react & custom hooks, render props, high-order components, and React State Management Libraries.
🟠 The state management libraries in React are pre-built code bundles that are added to the React frontend so that state management of components becomes easy.
🟠 There are various states of React components, such as local, global, fetch, UI state, server-caching, mutable, complex, etc.), and each has its essence.

Read the blog ahead for in-depth information about React State Management.

Why is State Management in React Enterprise Apps Crucial?

The most critical and challenging choice of a business owner is to build their enterprise application in such a manner that it is easy to maintain, can be reusable, delivers high performance, and the most essential is that the app must have a good scope of scalability.

React State Management is a striking topic in the web development domain, and when you have a React.js enterprise application, getting an in-depth grasp of the same is vital. As we know the pain points of business app development, let us check how state management React libraries can enable your enterprise app to match your business aims.

State Management in React enables the following:

Performance

React.js applications may have difficulty loading the frontend due to the re-renders. With React state management, you can optimize your state updates, resulting in better app performance and efficiency.

Maintenance

State management in React applications enables you to modularize and encapsulate state updates. Hence, you can easily maintain and debug your codebase. This maintainability also ensures that the new development team additions can quickly adapt and understand the applications’ states.

Reusability

It is difficult to reuse states across various components of a React application, but, using React state management libraries like Redux and MobX, you can easily share states across all the components of your application.

Scalability

A poor state management strategy leads to performance degradation and bugs, making it difficult to manage the states as the applications scale in size and complexity. React provides a well-designed state management strategy to ensure you can flawlessly scale your React js applications.

This is how State Management React is the wise solution for CTOs and Product owners.

Different Approaches to State Management in React

As you have a React Js application offering speed, flexibility, rich UI, and so much more, you would want to leverage the state of components in your application.

Find out the different ways to attain React state management:

Approaches to State Management in React

Component State

Each React component has its internal state, which can be 2used to store and manage data that is specific to that component. This state is managed using the setState method, which updates the component’s state and triggers a re-render.

Context API

The Context API is a built-in way to share the state between components in React without passing data down the component tree through props. This can be a useful alternative to using component state when you need to share state between components that are not directly connected in the component tree.

React Hooks

React Hooks are a way to add state and other React features to functional components. The useState and useReducer hooks can be used to manage local component state, while the useContext hook can be used to access shared state from the Context API.

Custom Hooks

Custom hooks are a way to extract state and logic into reusable functions that multiple components can use. This can be a good option for sharing state and logic between components that are not deeply nested in the component tree.

Higher-Order Components (HOCs)

Higher-Order Components are a way to share the state between components by wrapping components with another component that provides the state. This can be a good option for sharing the state between components not profoundly nested in the component tree.

Render Props

Render props is a pattern for sharing state between components by passing a function as a prop that renders the component that needs the state. This can be a good option for sharing the state between components not deeply nested in the component tree.

Besides the above, many State Management React Libraries are available for use. Let us find out more about them.

React State Management Tutorial

Let us get to a practical where we will learn how to manage states in an React application.

Objective: A simple increment/decrement application in React using the in-built state management features.

Step 1: Create a New React Project

npx create-react-app counter-app

Now, as your project is created, navigate to the src directory and create a new file called ‘counter.js’.

Step 2: Define the Main Function

First, let’s import React and create a new functional component called Counter. Inside the component, we’ll use the useState hook to create a new state variable called count and set it to an initial value of 0. We’ll also create two functions called increment and decrement that will be used to update the count variable:

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  const decrement = () => {
    setCount(count - 1);
  };

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </div>
  );
}

export default Counter;

In the code above, we’re using the useState hook to create a new state variable called count and a function called setCount that will be used to update the count variable. We’re setting the initial value of count to 0.

We’re also creating two functions called increment and decrement that will be called when the user clicks on the “+” and “-” buttons, respectively. Inside these functions, we’re calling the setCount function to update the value of count by either adding or subtracting 1.

Finally, we’re returning a div element that contains the current value of count, as well as two buttons that call the increment and decrement functions when clicked.

Step 3: Render the ‘Counter’ in the Main JS File

Now, let’s go to App.js file and render the Counter component:

import React from 'react';
import Counter from './Counter';

function App() {
  return (
    <div>
      <Counter />
    </div>
  );
}

export default App;

You should now be able to run the app by running npm start and see the counter application in your browser.

This was a simple example of handling and managing state in React application.

14 Top React State Management Libraries

Here are the popular libraries pre-built for state management in React js applications, along with their pros and cons.

React State Management Libraries

1. Redux

Redux is a popular state management library for building web applications with React, Angular, and other frameworks. It provides a centralized store to manage the state of an application and a set of rules for predictably modifying that state.

Pros: Predictable state management, debuggable, robust ecosystem, time-travel debugging, and efficient handling of complex state changes.

Cons: Can be complex to set up and configure, dependency on boilerplate code, not suitable for simple apps, and requires an understanding of functional programming concepts.

2. MobX

MobX is a react state management library that uses observables to track state changes and automatically re-render components when those observables change.

Pros: Simple and intuitive to use, minimal boilerplate, fast and efficient, excellent performance, and has strong compatibility with React.

Cons: Lacks some features of more complex state management libraries, can be harder to debug, and has a smaller ecosystem.

3. Recoil

Recoil is a state management library for React applications that was developed by Facebook. It provides a centralized store to manage the state of an application and a set of hooks for accessing and updating that state.

Pros: Simple, flexible, easy to learn and use, and outstanding performance.

Cons: A relatively new library, which is under development, and the community is not mature, but growing.

4. Jotai

Jotai, by Pedro Nauck, uses atoms and setters to manage the state of an application, focusing on simplicity and performance.

Pros: Simple and lightweight, easy to use, works well with React, and has a small learning curve.

Cons: A relatively new library, still under active development, and the ecosystem is not as mature as other libraries.

5. Zustand

Guillaume Salva gave the Zustand state management library for React, which uses a simplified Redux-like approach to manage the state of an application.

Pros: Simple and easy to use, with minimal boilerplate code, drives performance and has a small bundle size.

Cons: Not suggested for complex state management handling, and the ecosystem is still growing.

6. Rematch

Shawn McKay built this Redux-based state management library for React applications. It provides a simplified API for creating Redux stores and reducers, such that it reduces the dependency on boilerplate and improves developer productivity.

Pros: Easy to use and understand, using lesser boilerplate code than traditional Redux, and provides excellent performance.

Cons: Still requires a good understanding of Redux concepts, may not be suitable for large-scale projects, and has a smaller ecosystem than other options.

7. Hookstate

Hookstate is a relatively new state management library for React applications that was developed by Rafael Wieland. At its core, Hookstate uses a simplified approach to manage the state of an application, emphasizing performance and developer productivity.

Pros: Simple and easy to use, minimal boilerplate, and delivers high performance.

Cons: Can use for simple state management scenarios only, and has a smaller ecosystem.

8. Valtio

Poimandres came up with the Valtio state management library that uses a minimalistic and reactive approach to manage the state of an application, with a focus on performance and developer productivity.

Pros: Simple and easy to use, minimal boilerplate, and excellent performance.

Cons: Can only be used for simple state management scenarios, and has a smaller ecosystem than other options.

9. XState

David Khourshid developed the XState library, which uses the concept of finite state machines to manage the state of an application, focusing on predictability, modularity, and testability.

Pros: Excellent for managing complex state transitions, with a strong focus on declarative programming and strong typing.

Cons: May require more time to learn and understand and may not be suitable for simpler state management scenarios.

10. Unstated

Unstated is a lightweight state management library that uses the React context API to share state between components. It is a simpler alternative to Redux and MobX that can be used for smaller or simpler applications.

Pros: Simple and easy to use, with minimal boilerplate and good performance.

Cons: Not advisable for large-scale projects, and can have potential performance issues as it is dependent on Context API in React, which is slow in certain situations. Has a limited ecosystem and a long learning curve.

11. React-router

Ryan Florence and Michael Jackson developed this library for routing in React apps. React Router provides a declarative way to handle routing in a React application, focusing on simplicity, flexibility, and performance.

Pros: Powerful and flexible routing options and a large ecosystem.

Cons: Can be complex to set up and configure, and can lead to performance issues in some cases.

12. React-stately

Adobe developed the React-stately state management library, which at its core, provides a set of hooks and components that can be used to manage complex UI states, such as those found in form inputs, dropdowns, and menus.

Pros: Designed specifically for creating accessible user interfaces with good performance and a clean, composable API.

Cons: Not suitable for more complex state management scenarios.

13. React-powerhooks

Fabien Juif developed this library of reusable hooks for React applications. At its core, React Powerhooks provides a set of hooks that manage common UI states, such as loading, error handling, and form validation.

Pros: Provides a variety of useful hooks for common scenarios. These hooks require minimum setup.

Cons: Not suitable for more complex state management scenarios.

14. react-use-state-updater

Jed Watson developed this library that provides a hook to manage the state of a React component, with a focus on performance and developer productivity.

Pros: Improves the performance of React components that rely heavily on useState.

Cons: Only suitable for some use cases. It is less intuitive to use than the built-in useState hook.

All about ReactJs States

By far, we learned, understood, and discussed the states of components in ReactJs applications and how to handle and manage State Management in React. Let us now get to the core basics.

Here are the different states of React components:

different states of React components

Local State

The local state is specific to a single component and is managed using the setState method. It is typically used to stores component-specific data and is only used within that component.

Global State

The global state is shared between multiple components and manages the entire application’s global data. It is typically stored in a centralized store, such as a Redux store, an `d accessed by components through the store’s state.

Fetch State

This state is used to manage the data fetched from a remote server or API. The Fetch state is typically used to store information about the state of a fetch operation, such as whether the data has been loaded, if there was an error, or if the data is being loaded.

UI State

Manages the data that affects how the UI is displayed- data related to the user interface. Examples of UI state include whether a form is visible or a modal is open, the current selected tab, or the current scroll position.

Server-side Caching State

Stores the state on the server and is used to cache data for performance optimization. Server-side caching state is typically used to store data that does not change frequently, such as information about products or user profiles, to reduce the number of round trips to the server.

Mutable State

It refers to data that can change over time and is typically stored in the component state using the useState hook or in a class component’s state. The mutable state can be simple, such as a string or number, or more complex, such as an array or object. When the state updates, React will re-render the component and any child components that depend on that state.

Complex State

Refers to data derived from other data and is typically not directly mutable. Instead of being stored in a state, a complex state is calculated using the component’s props or other state variables. Examples of this include the results of a calculation, the filtered or sorted version of an array, or the current state of an animation. Because the complex state is not directly mutable, it doesn’t trigger re-renders of the component when it changes.

Conclusion

React state management is the most essential decision for entrepreneurs to build scalable, performant, and robust React applications. It ensures that our app remains in sync with the user interface. We saw the various in-built as well as third-party options to handle and manage states in React application. From the wide range of solutions, your choice depends on your project requirements, as well as the size of your development team.

Original article source at: https://www.bacancytechnology.com/

#react #state #management 

How to Everything About React State Management
Monty  Boehm

Monty Boehm

1676426820

Autopopulate Dropdown using jQuery AJAX in CakePHP 4

Autopopulate Dropdown using jQuery AJAX in CakePHP 4

Dynamic-dependent dropdowns are very helpful to restrict user selection. You may have already seen this on the registration or profile page of the website where you need to select country, state, and city. Options in the dropdown update every time when a country or state dropdown selection gets changed.

If your tables are properly interlinked in the database and want to list their data on the dropdown then you can make them dynamically dependent on one another and load their data using AJAX.

In this tutorial, I show how you can autopopulate dropdown using jQuery AJAX with MySQL database data in CakePHP 4.

Contents

  1. Create Table
  2. Database Configuration
  3. Create Model
  4. Create Controller
  5. Include jQuery and CSRF token
  6. Create Template
  7. Output
  8. Conclusion

1. Create Table

In the example, I am using 3 tables –

  • countries
  • states
  • cities

countries (Store countries name) –

CREATE TABLE `countries` (
    `id` int(10) UNSIGNED NOT NULL,
    `name` varchar(80) NOT NULL
);

ALTER TABLE `countries`
    ADD PRIMARY KEY (`id`);

ALTER TABLE `countries`
    MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;

states (Store country states names) –

Added foreign key on country_id field.

CREATE TABLE `states` (
    `id` int(10) UNSIGNED NOT NULL,
    `country_id` int(10) UNSIGNED NOT NULL,
    `name` varchar(80) NOT NULL
);

ALTER TABLE `states`
    ADD PRIMARY KEY (`id`),
    ADD KEY `states_country_id_foreign` (`country_id`);

ALTER TABLE `states`
    MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;

cities (Store state cities name) –

Added foreign key on state_id field.

CREATE TABLE `cities` (
    `id` int(10) UNSIGNED NOT NULL,
    `state_id` int(10) UNSIGNED NOT NULL,
    `name` varchar(80) NOT NULL
);

ALTER TABLE `cities`
    ADD PRIMARY KEY (`id`),
    ADD KEY `cities_state_id_foreign` (`state_id`);

ALTER TABLE `cities`
    MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;

2. Database Configuration

  • Open config/app_local.php file.
  • Specify your database configuration details in the Datasources default.
'Datasources' => [
     'default' => [
          'host' => '127.0.0.1',
          /*
          * CakePHP will use the default DB port based on the driver selected
          * MySQL on MAMP uses port 8889, MAMP users will want to uncomment
          * the following line and set the port accordingly
          */
          //'port' => 'non_standard_port_number',

          'username' => 'root',
          'password' => 'root',

          'database' => 'cakephp4',
          /*
          * If not using the default 'public' schema with the PostgreSQL driver
          * set it here.
          */
          //'schema' => 'myapp',

          /*
          * You can use a DSN string to set the entire configuration
          */
          'url' => env('DATABASE_URL', null),
     ],

     /*
     * The test connection is used during the test suite.
     */
     'test' => [
          'host' => 'localhost',
          //'port' => 'non_standard_port_number',
          'username' => 'my_app',
          'password' => 'secret',
          'database' => 'test_myapp',
          //'schema' => 'myapp',
          'url' => env('DATABASE_TEST_URL', 'sqlite://127.0.0.1/tests.sqlite'),
     ],
],

3. Create Model

Create 3 models –

  • Countries
  • States
  • Cities

Countries Model –

bin/cake bake model Countries

This will create 2 files  –

  • src/Model/Entity/Country.php
<?php
declare(strict_types=1);

namespace App\Model\Entity;

use Cake\ORM\Entity;

class Country extends Entity
{
     protected $_accessible = [ 
         'name' => true,
         'states' => true,
     ];
}
  • src/Model/Table/CountriesTable.php
<?php
declare(strict_types=1);

namespace App\Model\Table;

use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;

class CountriesTable extends Table
{
     public function initialize(array $config): void
     {
           parent::initialize($config);

           $this->setTable('countries');
           $this->setDisplayField('name');
           $this->setPrimaryKey('id');

           $this->hasMany('States', [
               'foreignKey' => 'country_id',
           ]);
     }

     public function validationDefault(Validator $validator): Validator
     {
           $validator
               ->scalar('name')
               ->maxLength('name', 255)
               ->requirePresence('name', 'create')
               ->notEmptyString('name');

           return $validator;
     }
}

States Model –

bin/cake bake model States

This will create 2 files –

  • src/Model/Entity/State.php
<?php
declare(strict_types=1);

namespace App\Model\Entity;

use Cake\ORM\Entity;

class State extends Entity
{
     protected $_accessible = [
         'country_id' => true,
         'name' => true,
         'country' => true,
         'cities' => true,
     ];
}
  • src/Model/Table/StatesTable.php
<?php
declare(strict_types=1);

namespace App\Model\Table;

use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;

class StatesTable extends Table
{

     public function initialize(array $config): void
     {
           parent::initialize($config);

           $this->setTable('states');
           $this->setDisplayField('name');
           $this->setPrimaryKey('id');

           $this->belongsTo('Countries', [
               'foreignKey' => 'country_id',
               'joinType' => 'INNER',
           ]);
           $this->hasMany('Cities', [
               'foreignKey' => 'state_id',
           ]);
     }

     public function validationDefault(Validator $validator): Validator
     {
           $validator
               ->notEmptyString('country_id');

           $validator
               ->scalar('name')
               ->maxLength('name', 255)
               ->requirePresence('name', 'create')
               ->notEmptyString('name');

           return $validator;
     }

     public function buildRules(RulesChecker $rules): RulesChecker
     {
           $rules->add($rules->existsIn('country_id', 'Countries'), ['errorField' => 'country_id']);

           return $rules;
     }
}

Cities Model –

This will create 2 files –

  • src/Model/Entity/City.php
<?php
declare(strict_types=1);

namespace App\Model\Entity;

use Cake\ORM\Entity;

class City extends Entity
{
     protected $_accessible = [
         'state_id' => true,
         'name' => true,
         'state' => true,
     ];
}
  • src/Model/Table/CitiesTable.php
<?php
declare(strict_types=1);

namespace App\Model\Table;

use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;

class CitiesTable extends Table
{

     public function initialize(array $config): void
     {
          parent::initialize($config);

          $this->setTable('cities');
          $this->setDisplayField('name');
          $this->setPrimaryKey('id');

          $this->belongsTo('States', [
              'foreignKey' => 'state_id',
              'joinType' => 'INNER',
          ]);
     }

     public function validationDefault(Validator $validator): Validator
     {
          $validator
              ->notEmptyString('state_id');

          $validator
              ->scalar('name')
              ->maxLength('name', 255)
              ->requirePresence('name', 'create')
              ->notEmptyString('name');

          return $validator;
     }

     public function buildRules(RulesChecker $rules): RulesChecker
     {
          $rules->add($rules->existsIn('state_id', 'States'), ['errorField' => 'state_id']);

          return $rules;
     }
}

4. Create Controller

  • Create a AutopopulateController.php file in src/Controller/ folder.
  • Create AutopopulateController Class that extends AppController.

Create 3 method –

  • index() – Fetch all records from the countries table. Loop on the fetched records and store them in $country_arr Array. Using $this->set() pass $country_arr Array to template.
  • getCountryStates() – Using this method return states list of the requested country from AJAX request.

Read POST country_id and assign it to the variable. Fetch all records from the states table where country_id = $country_id.

Loop on the fetch records and store state id and name in $data_arr Array. Return $data_arr Array in JSON format.

  • getStateCities() – Using this method return cities list of the requested state from AJAX request.

Read POST state_id and assign it to the variable. Fetch all records from the cities table where state_id = $state_id.

Loop on the fetch records and store city id and name in $data_arr Array. Return $data_arr Array in JSON format.

Completed Code

<?php
declare(strict_types=1);

namespace App\Controller;

class AutopopulateController extends AppController
{

     public function index(){

          ## Fetch all countries
          $countries = $this->getTableLocator()->get('Countries');
          $query = $countries->find('all')->order(['name' => 'ASC']);
          $countriesList = $query->toArray();

          $country_arr = array(); 
          foreach($countriesList as $country){
               $country_arr[$country['id']] = $country['name'];
          }

          $this->set(compact('country_arr'));
     }

     // Get country states
     public function getCountryStates(){

          // POST value
          $country_id = $this->request->getData()['country_id'];

          ## Fetch all states of country_id
          $states = $this->getTableLocator()->get('States');
          $query = $states->find('all')
               ->where(['country_id' => $country_id])
               ->order(['name' => 'ASC']);
          $statesList = $query->toArray();

          $data_arr = array();
          foreach($statesList as $state){
               $data_arr[] = array(
                   'id' => $state['id'],
                   'name' => $state['name']
               );
          }

          echo json_encode($data_arr);
          die;
     }

     // Get state cities
     public function getStateCities(){

          // POST value
          $state_id = $this->request->getData()['state_id'];

          ## Fetch all cities of state_id
          $cities = $this->getTableLocator()->get('Cities');
          $query = $cities->find('all')
              ->where(['state_id' => $state_id])
              ->order(['name' => 'ASC']);
          $citiesList = $query->toArray();

          $data_arr = array();
          foreach($citiesList as $city){
               $data_arr[] = array(
                   'id' => $city['id'],
                   'name' => $city['name']
               );
          }

          echo json_encode($data_arr);
          die;
     }

}

6. Include jQuery and CSRF token

I am including jQuery and CSRF token on templates/layout/default.php file.

Stored CSRF token in <meta > tag –

<?= $this->Html->meta('csrfToken', $this->request->getAttribute('csrfToken')); ?>

and jQuery in <head > section –

<?= $this->Html->script('https://code.jquery.com/jquery.min.js'); ?>

Completed Code

<?php
$cakeDescription = 'CakePHP: the rapid development php framework';
?>
<!DOCTYPE html>
<html>
<head>
     <?= $this->Html->charset() ?>
     <meta name="viewport" content="width=device-width, initial-scale=1">

     <!-- CSRF Token -->
     <?= $this->Html->meta('csrfToken', $this->request->getAttribute('csrfToken')); ?>
     <title>
           <?= $cakeDescription ?>:
           <?= $this->fetch('title') ?>
     </title>
     <?= $this->Html->meta('icon') ?>

     <link href="https://fonts.googleapis.com/css?family=Raleway:400,700" rel="stylesheet">

     <?= $this->Html->css(['normalize.min', 'milligram.min', 'cake']) ?>

     <!-- jQuery -->
     <?= $this->Html->script('https://code.jquery.com/jquery.min.js'); ?>

     <?= $this->fetch('meta') ?>
     <?= $this->fetch('css') ?>
     <?= $this->fetch('script') ?>
</head>
<body>
     <nav class="top-nav">
          <div class="top-nav-title">
               <a href="<?= $this->Url->build('/') ?>"><span>Cake</span>PHP</a>
          </div>
          <div class="top-nav-links">
               <a target="_blank" rel="noopener" href="https://book.cakephp.org/4/">Documentation</a>
               <a target="_blank" rel="noopener" href="https://api.cakephp.org/">API</a>
          </div>
     </nav>
     <main class="main">
          <div class="container">
               <?= $this->Flash->render() ?>
               <?= $this->fetch('content') ?>
          </div>
     </main>
     <footer>
     </footer>
</body>
</html>

6. Create Template

Create Autopopulate folder in templates/ location. In the Autopopulate folder create index.php file – templates/Autopopulate/index.php.

Create 3 <select > elements –

  • country – Display the passed country list from the controller.
  • state – Empty dropdown. Data load using jQuery AJAX when a country is been selected.
  • city – Empty dropdown. Data load using jQuery AJAX when a state is been selected.

jQuery

Read CSRF token from the <meta > tag and assign it to csrfToken variable.

Country Change –

Define change event on #country_id. Read selected country_id and empty the state and city dropdown. If country_id is not empty then send AJAX POST request to <?= $this->Url->build(['controller' => 'Autopopulate','action' => 'getCountryStates']) ?>.

Here, pass country_id – {country_id: country_id} as data, set dataType: 'json', pass CSRF token using header.

On successful callback loop on the response and add a new <option > in state dropdown.

State Change –

Define change event on #state_id. Read selected state_id and empty the city dropdown. If state_id is not empty then send AJAX POST request to <?= $this->Url->build(['controller' => 'Autopopulate','action' => 'getStateCities']) ?>.

Here, pass state_id – {state_id: state_id} as data, set dataType: 'json', pass CSRF token using header.

On successful callback loop on the response to add <option > in city dropdown.

Completed Code

<div class="row">
     <div class="col-6">

         <!-- Country -->
         <div id="input">
              <label for='country_id'>Country</label>
              <?php 
              echo $this->Form->select(
                  'country_id',
                  $country_arr,
                  [
                      'id' => 'country_id',
                      'empty' => '-- Select Country --'
                  ]
              );
              ?>
         </div>

         <!-- State -->
         <div id="input">
              <label for='state_id'>State</label>
              <?php 
              echo $this->Form->select(
                  'state_id',
                  [],
                  [
                      'id' => 'state_id',
                      'empty' => '-- Select State --'
                  ]
              );
              ?>
         </div>

         <!-- City -->
         <div id="input">
              <label for='city_id'>City</label>
              <?php 
              echo $this->Form->select(
                  'city_id',
                  [],
                  [
                      'id' => 'city_id',
                      'empty' => '-- Select City --'
                  ]
              );
              ?>
         </div>

     </div>
</div>
<!-- Script -->
<script type="text/javascript">
// Read CSRF Token
var csrfToken = $('meta[name="csrfToken"]').attr('content');
$(document).ready(function(){

     // Country change
     $('#country_id').change(function(){
          var country_id = $('#country_id').val();

          // Empty state and city dropdown
          $('#state_id').find('option').not(':first').remove();
          $('#city_id').find('option').not(':first').remove();

          if(country_id != ''){

               // AJAX request
               $.ajax({
                   url: "<?= $this->Url->build(['controller' => 'Autopopulate','action' => 'getCountryStates']) ?>",
                   type: 'post',
                   data: {country_id: country_id},
                   dataType: 'json',
                   headers:{
                        'X-CSRF-Token': csrfToken
                   },
                   success: function(response){

                        var len = response.length;

                        // Add response data to state dropdown
                        for( var i = 0; i<len; i++){
                             var id = response[i]['id'];
                             var name = response[i]['name'];

                             $("#state_id").append("<option value='"+id+"'>"+name+"</option>");

                        }
                   },
               });
          }

     });

     // State change
     $('#state_id').change(function(){
          var state_id = $('#state_id').val();

          // Empty city dropdown
          $('#city_id').find('option').not(':first').remove();

          if(state_id != ''){

               // AJAX request
               $.ajax({
                    url: "<?= $this->Url->build(['controller' => 'Autopopulate','action' => 'getStateCities']) ?>",
                    type: 'post',
                    data: {state_id: state_id},
                    dataType: 'json',
                    headers:{
                         'X-CSRF-Token': csrfToken
                    },
                    success: function(response){

                         var len = response.length;

                         // Add response data to city dropdown
                         for( var i = 0; i<len; i++){
                              var id = response[i]['id'];
                              var name = response[i]['name'];

                              $("#city_id").append("<option value='"+id+"'>"+name+"</option>");
                         }
                    },
               });
          }

     });

});
</script>

7. Output

View Output


8. Conclusion

In the example, I returned a JSON response from the server and looped on it to add a new item to the dropdown, but you can also return an HTML response and directly append it to the dropdown.

After implementing this on your project if data is not loading in the dropdown then debug it using the browser console and network tab.

If you found this tutorial helpful then don't forget to share.

Original article source at: https://makitweb.com/

#jquery #ajax #cakephp #php 

Autopopulate Dropdown using jQuery AJAX in CakePHP 4
Lawrence  Lesch

Lawrence Lesch

1673463960

UseStateMachine: The <1 Kb State Machine Hook for React

UseStateMachine

The <1 kb state machine hook for React:

See the user-facing docs at: usestatemachine.js.org

  • Batteries Included: Despite the tiny size, useStateMachine is feature complete (Entry/exit callbacks, Guarded transitions & Extended State - Context)
  • Amazing TypeScript experience: Focus on automatic type inference (auto completion for both TypeScript & JavaScript users without having to manually define the typings) while giving you the option to specify and augment the types for context & events.
  • Made for React: useStateMachine follow idiomatic React patterns you and your team are already familiar with. (The library itself is actually a thin wrapper around React's useReducer & useEffect.)

size badge

Examples

Installation

npm install @cassiozen/usestatemachine

Sample Usage

const [state, send] = useStateMachine({
  initial: 'inactive',
  states: {
    inactive: {
      on: { TOGGLE: 'active' },
    },
    active: {
      on: { TOGGLE: 'inactive' },
      effect() {
        console.log('Just entered the Active state');
        // Same cleanup pattern as `useEffect`:
        // If you return a function, it will run when exiting the state.
        return () => console.log('Just Left the Active state');
      },
    },
  },
});

console.log(state); // { value: 'inactive', nextEvents: ['TOGGLE'] }

// Refers to the TOGGLE event name for the state we are currently in.

send('TOGGLE');

// Logs: Just entered the Active state

console.log(state); // { value: 'active', nextEvents: ['TOGGLE'] }

API

useStateMachine

const [state, send] = useStateMachine(/* State Machine Definition */);

useStateMachine takes a JavaScript object as the state machine definition. It returns an array consisting of a current machine state object and a send function to trigger transitions.

state

The machine's state consists of 4 properties: value, event, nextEvents and context.

value (string): Returns the name of the current state.

event ({type: string}; Optional): The name of the last sent event that led to this state.

nextEvents (string[]): An array with the names of available events to trigger transitions from this state.

context: The state machine extended state. See "Extended State" below.

Send events

send takes an event as argument, provided in shorthand string format (e.g. "TOGGLE") or as an event object (e.g. { type: "TOGGLE" })

If the current state accepts this event, and it is allowed (see guard), it will change the state machine state and execute effects.

You can also send additional data with your event using the object notation (e.g. { type: "UPDATE" value: 10 }). Check schema for more information about strong typing the additional data.

State Machine definition

KeyRequiredDescription
verbose If true, will log every context & state changes. Log messages will be stripped out in the production build.
schema For usage with TypeScript only. Optional strongly-typed context & events. More on schema below
context Context is the machine's extended state. More on extended state below
initial*The initial state node this machine should be in
states*Define the possible finite states the state machine can be in.

Defining States

A finite state machine can be in only one of a finite number of states at any given time. As an application is interacted with, events cause it to change state.

States are defined with the state name as a key and an object with two possible keys: on (which events this state responds to) and effect (run arbitrary code when entering or exiting this state):

On (Events & transitions)

Describes which events this state responds to (and to which other state the machine should transition to when this event is sent):

states: {
  inactive: {
    on: {
      TOGGLE: 'active';
    }
  },
  active: {
    on: {
      TOGGLE: 'inactive';
    }
  },
},

The event definition can also use the extended, object syntax, which allows for more control over the transition (like adding guards):

on: {
  TOGGLE: {
    target: 'active',
  },
};

Guards

Guards are functions that run before actually making the state transition: If the guard returns false the transition will be denied.

const [state, send] = useStateMachine({
  initial: 'inactive',
  states: {
    inactive: {
      on: {
        TOGGLE: {
          target: 'active',
          guard({ context, event }) {
            // Return a boolean to allow or block the transition
          },
        },
      },
    },
    active: {
      on: { TOGGLE: 'inactive' },
    },
  },
});

The guard function receives an object with the current context and the event. The event parameter always uses the object format (e.g. { type: 'TOGGLE' }).

Effects (entry/exit callbacks)

Effects are triggered when the state machine enters a given state. If you return a function from your effect, it will be invoked when leaving that state (similarly to how useEffect works in React).

const [state, send] = useStateMachine({
  initial: 'active',
  states: {
    active: {
      on: { TOGGLE: 'inactive' },
      effect({ send, setContext, event, context }) {
        console.log('Just entered the Active state');
        return () => console.log('Just Left the Active state');
      },
    },
  },
});

The effect function receives an object as parameter with four keys:

  • send: Takes an event as argument, provided in shorthand string format (e.g. "TOGGLE") or as an event object (e.g. { type: "TOGGLE" })
  • setContext: Takes an updater function as parameter to set a new context (more on context below). Returns an object with send, so you can set the context and send an event on a single line.
  • event: The event that triggered a transition to this state. (The event parameter always uses the object format (e.g. { type: 'TOGGLE' }).).
  • context The context at the time the effect runs.

In this example, the state machine will always send the "RETRY" event when entering the error state:

const [state, send] = useStateMachine({
  initial: 'loading',
  states: {
    /* Other states here... */
    error: {
      on: {
        RETRY: 'load',
      },
      effect({ send }) {
        send('RETRY');
      },
    },
  },
});

Extended state (context)

Besides the finite number of states, the state machine can have extended state (known as context).

You can provide the initial context value in the state machine definition, then use the setContext function within your effects to change the context:

const [state, send] = useStateMachine({
  context: { toggleCount: 0 },
  initial: 'inactive',
  states: {
    inactive: {
      on: { TOGGLE: 'active' },
    },
    active: {
      on: { TOGGLE: 'inactive' },
      effect({ setContext }) {
        setContext(context => ({ toggleCount: context.toggleCount + 1 }));
      },
    },
  },
});

console.log(state); // { context: { toggleCount: 0 }, value: 'inactive', nextEvents: ['TOGGLE'] }

send('TOGGLE');

console.log(state); // { context: { toggleCount: 1 }, value: 'active', nextEvents: ['TOGGLE'] }

Schema: Context & Event Typing

TypeScript will automatically infer your context type; event types are generated automatically.

Still, there are situations where you might want explicit control over the context and event types: You can provide you own typing using the t whithin schema:

Typed Context example

const [state, send] = useStateMachine({
  schema: {
    context: t<{ toggleCount: number }>()
  },
  context: { toggleCount: 0 },
  initial: 'inactive',
  states: {
    inactive: {
      on: { TOGGLE: 'active' },
    },
    active: {
      on: { TOGGLE: 'inactive' },
      effect({ setContext }) {
        setContext(context => ({ toggleCount: context.toggleCount + 1 }));
      },
    },
  },
});

Typed Events

All events are type-infered by default, both in the string notation (send("UPDATE")) and the object notation (send({ type: "UPDATE"})).

If you want, though, you can augment an already typed event to include arbitrary data (which can be useful to provide values to be used inside effects or to update the context). Example:

const [machine, send] = useStateMachine({
  schema: {
    context: t<{ timeout?: number }>(),
    events: {
      PING: t<{ value: number }>()
    }
  },
  context: {timeout: undefined},
  initial: 'waiting',
  states: {
    waiting: {
      on: {
        PING: 'pinged'
      }
    },
    pinged: {
      effect({ setContext, event }) {
        setContext(c => ({ timeout: event?.value ?? 0 }));
      },
    }
  },
});

send({ type: 'PING', value: 150 })

Note that you don't need to declare all your events in the schema, only the ones you're adding arbitrary keys and values.

Wiki

Download Details:

Author: Cassiozen
Source Code: https://github.com/cassiozen/useStateMachine 
License: MIT license

#typescript #hooks #state #management 

UseStateMachine: The <1 Kb State Machine Hook for React
Nigel  Uys

Nigel Uys

1673460600

Install / Configure Docker and Docker Compose using Ansible

What is ansible-docker? 

It is an Ansible role to:

  • Install Docker (editions, channels and version pinning are all supported)
  • Install Docker Compose v1 and Docker Compose v2 (version pinning is supported)
  • Install the docker PIP package so Ansible's docker_* modules work
  • Manage Docker registry login credentials
  • Configure 1 or more users to run Docker without needing root access
  • Configure the Docker daemon's options and environment variables
  • Configure a cron job to run Docker clean up commands

Why would you want to use this role?

If you're like me, you probably love Docker. This role provides everything you need to get going with a production ready Docker host.

By the way, if you don't know what Docker is, or are looking to become an expert with it then check out Dive into Docker: The Complete Docker Course for Developers.

Supported platforms

  • Ubuntu 20.04 LTS (Focal Fossa)
  • Ubuntu 22.04 LTS (Jammy Jellyfish)
  • Debian 10 (Buster)
  • Debian 11 (Bullseye)

You are viewing the master branch's documentation which might be ahead of the latest release. Switch to the latest release.


Quick start

The philosophy for all of my roles is to make it easy to get going, but provide a way to customize nearly everything.

What's configured by default?

The latest Docker CE, Docker Compose v1 and Docker Compose v2 will be installed, Docker disk clean up will happen once a week and Docker container logs will be sent to journald.

Example playbook

---

# docker.yml

- name: Example
  hosts: "all"
  become: true

  roles:
    - role: "nickjj.docker"
      tags: ["docker"]

Usage: ansible-playbook docker.yml

Installation

$ ansible-galaxy install nickjj.docker

Default role variables

Installing Docker

Edition

Do you want to use "ce" (community edition) or "ee" (enterprise edition)?

docker__edition: "ce"

Channel

Do you want to use the "stable", "edge", "testing" or "nightly" channels? You can add more than one (order matters).

docker__channel: ["stable"]

Version

  • When set to "", the current latest version of Docker will be installed
  • When set to a specific version, that version of Docker will be installed and pinned
docker__version: ""

# For example, pin it to 20.10.
docker__version: "20.10"

# For example, pin it to a more precise version of 20.10.
docker__version: "20.10.17"

Pins are set with * at the end of the package version so you will end up getting minor and security patches unless you pin an exact version.

Upgrade strategy

  • When set to "present", running this role in the future won't install newer versions (if available)
  • When set to "latest", running this role in the future will install newer versions (if available)
docker__state: "present"

Downgrade strategy

The easiest way to downgrade would be to uninstall the Docker package manually and then run this role afterwards while pinning whatever specific Docker version you want.

# An ad-hoc Ansible command to stop and remove the Docker CE package on all hosts.
ansible all -m systemd -a "name=docker-ce state=stopped" \
  -m apt -a "name=docker-ce autoremove=true purge=true state=absent" -b

Installing Docker Compose v2

Docker Compose v2 will get apt installed using the official docker-compose-plugin that Docker manages.

Version

  • When set to "", the current latest version of Docker Compose v2 will be installed
  • When set to a specific version, that version of Docker Compose v2 will be installed and pinned
docker__compose_v2_version: ""

# For example, pin it to 2.6.
docker__compose_v2_version: "2.6"

# For example, pin it to a more precise version of 2.6.
docker__compose_v2_version: "2.6.0"

Upgrade strategy

It'll re-use the docker__state variable explained above in the Docker section with the same rules.

Downgrade strategy

Like Docker itself, the easiest way to uninstall Docker Compose v2 is to manually run the command below and then pin a specific Docker Compose v2 version.

# An ad-hoc Ansible command to remove the Docker Compose Plugin package on all hosts.
ansible all -m apt -a "name=docker-compose-plugin autoremove=true purge=true state=absent" -b

Installing Docker Compose v1

Docker Compose v1 will get PIP installed inside of a Virtualenv. If you plan to use Docker Compose v2 instead it will be very easy to skip installing v1 although technically both can be installed together since v1 is accessed with docker-compose and v2 is accessed with docker compose (notice the lack of hyphen).

In any case details about this is covered in detail in a later section of this README file.

Version

  • When set to "", the current latest version of Docker Compose v1 will be installed
  • When set to a specific version, that version of Docker Compose v1 will be installed and pinned
docker__compose_version: ""

# For example, pin it to 1.29.
docker__compose_version: "1.29"

# For example, pin it to a more precise version of 1.29.
docker__compose_version: "1.29.2"

Upgrade and downgrade strategies will be explained in the other section of this README.

Configuring users to run Docker without root

A list of users to be added to the docker group.

Keep in mind this user needs to already exist, this role will not create it. If you want to create users, check out my user role.

This role does not configure User Namespaces or any other security features by default. If the user you add here has SSH access to your server then you're effectively giving them root access to the server since they can run Docker without sudo and volume mount in any path on your file system.

In a controlled environment this is safe, but like anything security related it's worth knowing this up front. You can enable User Namespaces and any other options with the docker__daemon_json variable which is explained later.

# Try to use the sudo user by default, but fall back to root.
docker__users: ["{{ ansible_env.SUDO_USER | d('root') }}"]

# For example, if the user you want to set is different than the sudo user.
docker__users: ["admin"]

Configuring Docker registry logins

Login to 1 or more Docker registries (such as the Docker Hub).

# Your login credentials will end up in this user's home directory.
docker__login_become_user: "{{ docker__users | first | d('root') }}"
# 0 or more registries to log into.
docker__registries:
  - #registry_url: "https://index.docker.io/v1/"
    username: "your_docker_hub_username"
    password: "your_docker_hub_password"
    #email: "your_docker_hub@emailaddress.com"
    #reauthorize: false
    #config_path: "$HOME/.docker/config.json"
    #state: "present"
docker__registries: []

Properties prefixed with * are required.

  • registry_url defaults to https://index.docker.io/v1/
  • *username is your Docker registry username
  • *password is your Docker registry password
  • email defaults to not being used (not all registries use it)
  • reauthorize defaults to false, when true it updates your credentials
  • config_path defaults to your docker__login_become_user's $HOME directory
  • state defaults to "present", when "absent" the login will be removed

Configuring the Docker daemon options (json)

Default Docker daemon options as they would appear in /etc/docker/daemon.json.

docker__default_daemon_json: |
  "log-driver": "journald",
  "features": {
    "buildkit": true
  }

# Add your own additional daemon options without overriding the default options.
# It follows the same format as the default options, and don't worry about
# starting it off with a comma. The template will add the comma if needed.
docker__daemon_json: ""

Configure the Docker daemon options (flags)

Flags that are set when starting the Docker daemon cannot be changed in the daemon.json file. By default Docker sets -H unix:// which means that option cannot be changed with the json options.

Add or change the starting Docker daemon flags by supplying them exactly how they would appear on the command line.

# Each command line flag should be its own item in the list.
#
# Using a Docker version prior to 18.09?
#   You must set `-H fd://` instead of `-H unix://`.
docker__daemon_flags:
  - "-H unix://"

If you don't supply some type of -H flag here, Docker will fail to start.

Configuring the Docker daemon environment variables

docker__daemon_environment: []

# For example, here's how to set a couple of proxy environment variables.
docker__daemon_environment:
  - "HTTP_PROXY=http://proxy.example.com:80"
  - "HTTPS_PROXY=https://proxy.example.com:443"

Configuring advanced systemd directives

This role lets the Docker package manage its own systemd unit file and adjusts things like the Docker daemon flags and environment variables by using the systemd override pattern.

If you know what you're doing, you can override or add to any of Docker's systemd directives by setting this variable. Anything you place in this string will be written to /etc/systemd/system/docker.service.d/custom.conf as is.

docker__systemd_override: ""

Configuring Docker related cron jobs

By default this will safely clean up disk space used by Docker every Sunday at midnight.

# `a` removes unused images (useful in production).
# `f` forces it to happen without prompting you to agree.
docker__cron_jobs_prune_flags: "af"

# Control the schedule of the docker system prune.
docker__cron_jobs_prune_schedule: ["0", "0", "*", "*", "0"]

docker__cron_jobs:
  - name: "Docker disk clean up"
    job: "docker system prune -{{ docker__cron_jobs_prune_flags }} > /dev/null 2>&1"
    schedule: "{{ docker__cron_jobs_prune_schedule }}"
    cron_file: "docker-disk-clean-up"
    #user: "{{ (docker__users | first) | d('root') }}"
    #state: "present"

Properties prefixed with * are required.

  • *name is the cron job's description
  • *job is the command to run in the cron job
  • *schedule is the standard cron job format for every Sunday at midnight
  • *cron_file writes a cron file to /etc/cron.d instead of a user's individual crontab
  • user defaults to the first docker__users user or root if that's not available
  • state defaults to "present", when "absent" the cron file will be removed

Configuring the APT package manager

Docker requires a few dependencies to be installed for it to work. You shouldn't have to edit any of these variables.

# List of packages to be installed.
docker__package_dependencies:
  - "apt-transport-https"
  - "ca-certificates"
  - "cron"
  - "gnupg2"
  - "software-properties-common"

# Ansible identifies CPU architectures differently than Docker.
docker__architecture_map:
  "x86_64": "amd64"
  "aarch64": "arm64"
  "aarch": "arm64"
  "armhf": "armhf"
  "armv7l": "armhf"

# The Docker GPG key id used to sign the Docker package.
docker__apt_key_id: "9DC858229FC7DD38854AE2D88D81803C0EBFCD88"

# The Docker GPG key server address.
docker__apt_key_url: "https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg"

# The Docker upstream APT repository.
docker__apt_repository: >
  deb [arch={{ docker__architecture_map[ansible_architecture] }}]
  https://download.docker.com/linux/{{ ansible_distribution | lower }}
  {{ ansible_distribution_release }} {{ docker__channel | join (' ') }}

Installing Python packages with Virtualenv and PIP

Configuring Virtualenv

Rather than pollute your server's version of Python, all PIP packages are installed into a Virtualenv of your choosing.

docker__pip_virtualenv: "/usr/local/lib/docker/virtualenv"

Installing PIP and its dependencies

This role installs PIP because Docker Compose v1 is installed with the docker-compose PIP package and Ansible's docker_* modules use the docker PIP package.

docker__pip_dependencies:
  - "gcc"
  - "python3-setuptools"
  - "python3-dev"
  - "python3-pip"
  - "virtualenv"

Installing PIP packages

docker__default_pip_packages:
  - name: "docker"
    state: "{{ docker__pip_docker_state }}"
  - name: "docker-compose"
    version: "{{ docker__compose_version }}"
    path: "/usr/local/bin/docker-compose"
    src: "{{ docker__pip_virtualenv + '/bin/docker-compose' }}"
    state: "{{ docker__pip_docker_compose_state }}"

# Add your own PIP packages with the same properties as above.
docker__pip_packages: []

Properties prefixed with * are required.

  • *name is the package name
  • version is the package version to be installed (or "" if this is not defined)
  • path is the destination path of the symlink
  • src is the source path to be symlinked
  • state defaults to "present", other values can be "forcereinstall" or "absent"

PIP package state

  • When set to "present", the package will be installed but not updated on future runs
  • When set to "forcereinstall", the package will always be (re)installed and updated on future runs
  • When set to "absent", the package will be removed
docker__pip_docker_state: "present"
docker__pip_docker_compose_state: "present"

Skipping the installation of Docker Compose v1

You can set docker__pip_docker_compose_state: "absent" in your inventory. That's it!

Honestly, in the future I think this will be the default behavior. Since Docker Compsose v2 is still fairly new I wanted to ease into using v2. There's also no harm in having both installed together. You can pick which one to use.

Working with Ansible's docker_* modules

This role uses docker_login to login to a Docker registry, but you may also use the other docker_* modules in your own roles. They are not going to work unless you instruct Ansible to use this role's Virtualenv.

At either the inventory, playbook or task level you'll need to set ansible_python_interpreter: "/usr/bin/env python3-docker". This works because this role creates a proxy script from the Virtualenv's Python binary to python3-docker.

You can look at this role's docker_login task as an example on how to do it at the task level.

Download Details:

Author: nickjj
Source Code: https://github.com/nickjj/ansible-docker 
License: MIT license

#ansible #docker 

Install / Configure Docker and Docker Compose using Ansible
Rupert  Beatty

Rupert Beatty

1670592011

How to Create Dynamic Dependent Dropdown with PostgreSQL PHP and AJAX

By auto-populating dropdown you can restrict users selection based on the parent dropdown selection.

Data is changed on child dropdowns every time selection is changed.

In this tutorial, I show how you can create dynamic dependent dropdown with PostgreSQL data using jQuery AJAX and PHP.

Contents

  1. Table structure
  2. Configuration
  3. HTML
  4. PHP
  5. jQuery
  6. Output
  7. Conclusion

1. Table structure

I am using 3 tables in the example –

countries table (Store countries records) –

CREATE TABLE countries (
  id serial PRIMARY KEY,
  name varchar(80) NOT NULL
)

states table (Store states of the countries) –

CREATE TABLE states (
  id serial PRIMARY KEY,
  name varchar(80) NOT NULL,
  country_id bigint NOT NULL
)

cities table (Store cities of the states) –

CREATE TABLE cities (
  id serial PRIMARY KEY,
  name varchar(80) NOT NULL,
  state_id bigint NOT NULL
)

2. Configuration

Create a new config.php file.

Completed Code

<?php

$host = "localhost";
$user = "postgres";
$password = "root";
$dbname = "tutorial";
$con = pg_connect("host=$host dbname=$dbname user=$user password=$password");

if (!$con) {
   die('Connection failed.');
}

3. HTML

Fetch records from countries table and create 3 <select> elements –

  • First <select > element is to display fetched countries.
  • Second is use to display states based on country selection using jQuery AJAX, and
  • Third is use to display cities based on state selection using jQuery AJAX.

Completed Code

<?php
include "config.php";

$sql = "select * from countries order by name";
$result = pg_query($con, $sql);
?>
<table>
   <tr>
      <td>Country</td>
      <td>
         <select id="country">
            <option value="0" >– Select Country –</option>
            <?php
            while ($row = pg_fetch_assoc($result) ){

               $id = $row['id'];
               $name = $row['name'];

               echo "<option value='".$id."' >".$name."</option>";
            }
            ?>
         </select>
      </td>
   </tr>

   <tr>
      <td>State</td>
      <td>
         <select id="state" >
            <option value="0" >– Select State –</option>
         </select>
      </td>
   </tr>

   <tr>
      <td>City</td>
      <td>
         <select id="city" >
            <option value="0" >– Select City –</option>
         </select>
      </td>
   </tr>
</table>

4. PHP

Create ajaxfile.php file.

Handle 2 AJAX requests –

  • If $request == ‘getStates’ – Fetch records from states table according to $country_id value and assign to $result. Loop on $result and initialize $data Array with id and name keys.

Return $data in JSON format.

  • If $request == ‘getCities’ – Fetch records from cities table according to $state_id value and assign to $result. Loop on $result and initialize $data Array with id and name keys.

Return $data in JSON format.

Completed Code

<?php
include 'config.php';

$request = "";
if(isset($_POST['request'])){
   $request = $_POST['request'];
}

// Get states
if($request == 'getStates'){
   $country_id = 0;
   $result = array();$data = array();

   if(isset($_POST['country_id'])){
      $country_id = $_POST['country_id'];

      $sql = "select * from states where country_id=$1";
      $result = pg_query_params($con, $sql, array($country_id));

      while ($row = pg_fetch_assoc($result) ){

         $id = $row['id'];
         $name = $row['name'];

         $data[] = array(
            "id" => $id,
            "name" => $name
         );

      }
   }

   echo json_encode($data);
   die;

}

// Get cities
if($request == 'getCities'){
   $state_id = 0;
   $result = array();$data = array();

   if(isset($_POST['state_id'])){
      $state_id = $_POST['state_id'];

      $sql = "select * from cities where state_id=$1";
      $result = pg_query_params($con, $sql, array($state_id));

      while ($row = pg_fetch_assoc($result) ){

         $id = $row['id'];
         $name = $row['name'];

         $data[] = array(
            "id" => $id,
            "name" => $name
         );

      }
   }

   echo json_encode($data);
   die;
}

5. jQuery

Define change event on #country and #state.

  • country – If a country is selected then empty the #state, and #city dropdown. Send AJAX POST request to ajaxfile.php, pass {request: 'getStates', country_id: country_id} as data, and set dataType: 'json'.

On successful callback loop on response and add <option > in #state.

  • state – If a state is selected then empty the #city dropdown and send AJAX POST request to ajaxfile.php, pass {request: 'getCities', state_id: state_id} as data, and set dataType: 'json'.

On successful callback loop on response and add <option > in #city.

Completed Code

$(document).ready(function(){

   // Country
   $('#country').change(function(){

      // Country id
      var country_id = $(this).val();

      // Empty the dropdown
      $('#state').find('option').not(':first').remove();
      $('#city').find('option').not(':first').remove();

      // AJAX request
      $.ajax({
         url: 'ajaxfile.php',
         type: 'post',
         data: {request: 'getStates', country_id: country_id},
         dataType: 'json',
         success: function(response){

            var len = 0;
            if(response != null){
               len = response.length;
            }

            if(len > 0){
               // Read data and create <option >
               for(var i=0; i<len; i++){

                  var id = response[i].id;
                  var name = response[i].name;

                  var option = "<option value='"+id+"'>"+name+"</option>";

                  $("#state").append(option);
               }
            }
         }
      });
   });

   // Country
   $('#state').change(function(){

      // State id
      var state_id = $(this).val();

      // Empty the dropdown
      $('#city').find('option').not(':first').remove();

      // AJAX request
      $.ajax({
         url: 'ajaxfile.php',
         type: 'post',
         data: {request: 'getCities', state_id: state_id},
         dataType: 'json',
         success: function(response){

            var len = 0;
            if(response != null){
               len = response.length;
            }

            if(len > 0){
               // Read data and create <option >
               for(var i=0; i<len; i++){

                  var id = response[i].id;
                  var name = response[i].name;

                  var option = "<option value='"+id+"'>"+name+"</option>";

                  $("#city").append(option);
               }
            }

         }
      });
   });

});

6. Output

View Output


7. Conclusion

In the example, I am auto-populating two dropdowns but you can follow the same steps to add it on more dropdowns.

If data is not loading in the dropdown then use the browser network tab to debug.

If you found this tutorial helpful then don't forget to share.

Original article source at: https://makitweb.com/

#postgresql #php #ajax 

How to Create Dynamic Dependent Dropdown with PostgreSQL PHP and AJAX
Nat  Grady

Nat Grady

1669018338

Difference Between Props and State in React

Let's learn the difference between Props and State in React.

In React library, props and states are both means to make a component more dynamic. Props (or properties) are inputs passed down from a parent component to its child component. On the other hand, states are variables defined and managed by the component.

In React library, props and states are both means to make a component more dynamic. Props (or properties) are inputs passed down from a parent component to its child component. On the other hand, states are variables defined and managed by the component.

For example, let’s say we have a that calls a :

function ParentComponent(){
  return <ChildComponent />
}

You can pass a prop from ParentComponent into ChildComponent by adding new attributes after the component name. For example, the name prop with value John is passed to ChildComponent below:

function ParentComponent(){
  return <ChildComponent name="John" />
}

After that, the child component will accept the props as the first argument. What to do with the prop being passed down to the child is of no concern to the parent component. You can simply output the name prop like this:

function ChildComponent(props){
  return <p> Hello World! my name is {props.name}</p>
}

In most real projects, the child component would probably render conditionally based on the props being passed into it:

export default function ParentComponent() {
  return <ChildComponent name="John" />
}

function ChildComponent(props) {
  if (props.name) {
    return <p> Hello World! my name is {props.name}</p>
  }
  return <p>Name not found. Please send me a "name" . . . </p>
}

Passing down multiple props

You can pass as many props as you want into a single child component, just write the props next to the previous. Here’s an example:

function ParentComponent() {
  return (
    <ChildComponent
      name="John"
      Age={29}
      isMale={true}
      hobbies={["read books", "drink coffee"]}
      occupation="Software Engineer"
    />
  );
}

Oh and please remember: you need to pass either a string or a JavaScript expression inside curly brackets as the value of props. This is because your component call is in JSX syntax, and you need to use curly brackets to write an expression.

Props are immutable

Meaning that a prop’s value can’t be changed no matter what happens. The following example will still output “John” instead of “Mark”:

function ChildComponent(props) {
  if (props.name) {
    props.name = "Mark";
    return <p> Hello World! my name is {props.name}</p>;
  }
  return <p>Name not found. Please send me a "name" . . . </p>;
}

But what if you need variables that might change later? This is where state comes in. States are arbitrary data that you can define, but they are initialized and managed by a component. Here’s how you define a function component state:

function ParentComponent() {
  const [name, setName] = React.useState("John")
}

In the example below, the name state is initialized by calling React.useState function. The useState function returns an array with two elements, the first element is the value of the state (in this case, “John”) and the second element is a function that you need to call to change the state value.

The square bracket surrounding both name and setName is a destructuring array assignment, meaning we take the return value of useState function, and directly assign them to name and setName variables.

Please note that you can’t change state value by reassigning the variable:

function ParentComponent() {
  const [name, setName] = React.useState("John")

  name = "Mark"
}

You need to use the function returned by useState as the second element:

function ParentComponent() {
  const [name, setName] = React.useState("");
  if (name === "") {
    setName("Mark");
  }
}

Also, never call on the set function at the top-level since it will cause an infinite loop:

function ParentComponent() {
  const [name, setName] = React.useState("");
  setName("Mark");
}

You can pass both state and its update function into any child component as a prop when required:

export default function ParentComponent() {
  const [name, setName] = React.useState("John");
  return <ChildComponent name={name} setName={setName} />;
}

When a child component needs the state to change, you can do so by calling on the setName function. In the following example, I put a button to change the value of name when it gets clicked:

function ChildComponent(props) {
  if (props.name) {
    return (
      <>
        <p> Hello World! my name is {props.name}</p>
        <button onClick={() => props.setName("Mark")}>Change name</button>
      </>
    );
  }
  return <p>Name not found. Please send me a "name" . . . </p>;
}

Here’s a codesandbox example that you can play with:

Conclusion

You’ve just learned the difference between props and state in React. Both features are simply arbitrary variables that you can use to make your React components more dynamic. In most cases, states are initialized at top-level components and passed down as props into children components.

When you need to change the prop value, the child component can send a signal — usually function call when a button is clicked or something similar — to the parent component to change the state. This will make the props value being passed down from the parent component to child component changes.

The components will then render the user interface accordingly.

Original article source at: https://sebhastian.com/

#react #prop #state 

Difference Between Props and State in React