In my React Redux project, I am writing a thunk, and want it to dispatch only if the previous update if any has been completed. I'm aware that thunks are methods that help us delay dispatching actions to the reducer, and they can also be asynchronous. Here is what my thunk looks like right now:
myThunkMethod = () => async (dispatch, getState) =>{
dispatch(...my action...);
}
but I how can make dispatch be called only after the previous call / state update is complete
Here is what you need to do:
const firstThunk = () => (dispatch, getState) => {
// do or dispatch something here
return Promise.resoleved("first thunk resolved");
}
const secondThunk = () => (dispatch, getState) => {
// do or dispatch something here
return Promise.resolved("second thunk resolved")
}
const thirdThunk = () => (dispatch, getState) => {
// I want to first dispatch the first thunk
dispatch(firstThunk()).then(result => {
// first thunk successfully dispatched now it's time for secondThunk
dispatch(secondThunk()).then(res => {
// here both firstThunk and secondThunk dispatched successfully
})
})
}
You can combine and wait for thunks to complete as long as your thunk returns a promise: (dispatch,getState)=>Promise.
const thunkA = (arg) => (dispatch, getState) => {
//do stuff and RETURN PROMISE
return Promise;
};
const thunkB = (arg) => (dispatch, getState) => {
//do stuff and RETURN PROMISE
return Promise;
};
//combined thunk
const combinedThunk = (arg) => (dispatch, getState) =>
tunkA(arg)(dispatch, getState).then(() =>
thunkB(arg)(dispatch, getState)
);
//from component
const Component = () => {
const dispatch = React.useDispatch();
React.useEffect(() => {
dispatch(thunkA("some arg")).then(() =>
dispatch(thunkB("someArg"))
);
}, [dispatch]);
};
Here is how you can do a recursive thunk:
const recursiveThunk = (times) => (dispatch, getState) => {
if (times === 0) {
return;
}
dispatch(started());
somePromise().then(
(result) => {
dispatch(success());
return recursiveThunk(times - 1)(dispatch, getState);
},
(reject) => dispatch(failed())
);
};
It is unclear what you want in your question and your comment but if you want to call thunkA each time with an item from an array as parameter then you can do this:
const combinedThunk = (args) => (dispatch, getState) => {
if (args.length === 0) {
return;
}
return tunkA(args[0])(dispatch, getState).then(
() => combinedThunk(args.slice(1))(dispatch, getState),
(reject) => dispatch(failed(reject))
);
};
//call thunkA with 1, then 2 and then 3
dispatch(combinedThunk([1, 2, 3]));
Related
I use Gutenberg with WordPress for a website with students.
I would like to display a list with all students (roles : student)
and exclude from the list the student who is logged in.
I tried two solutions.
First solution with getUsers() function. When I'm logged like an administrator all works fine but when a student is logged, he does not have permission to view the list. Only administrators have permission.
Second solution with a custom API route. I got a promise pending.
First solution :
import { __ } from '#wordpress/i18n';
import { CheckboxControl } from '#wordpress/components';
import { registerPlugin } from '#wordpress/plugins';
import { PluginDocumentSettingPanel } from '#wordpress/edit-post';
import { useSelect, useDispatch } from '#wordpress/data';
import { useEntityProp } from '#wordpress/core-data';
import { useState, setState, useEffect } from '#wordpress/element';
const metaboxStudents = () => {
const postType = useSelect( ( select ) => {
return select( 'core/editor' ).getCurrentPostType();
});
if ( postType !== 'subject-imposed' ) {
return null;
}
const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta' );
const authors = useSelect( ( select ) => {
return select( 'core' ).getUsers( { roles: 'student' } );
}, [] );
if ( !posts ) {
return null;
}
const handleCheckboxChange = (data) => {
const isChecked = meta._metafield_students.some(checkedCheckbox => checkedCheckbox === data);
if (isChecked) {
setMeta( { _metafield_students: meta._metafield_students.filter( ( checkedCheckbox) => checkedCheckbox !== data) } );
} else {
setMeta( { _metafield_students: meta._metafield_students.concat(data) } );
}
};
return(
<PluginDocumentSettingPanel
name="list-students"
title={ __( 'List of students', 'ccn-gut' ) }
className='editor-styles-metabox'
>
<div className="gut-checkboxes-group">
{ posts.map( ( data ) => (
wp.data.select("core").getCurrentUser().id !== data.id
? (
<CheckboxControl
label={ data.name }
key={`student-${data.id}`}
value={ data.id }
checked={ meta._metafield_students.some(checkedCheckbox => checkedCheckbox === data.id) }
onChange={ () => handleCheckboxChange(data.id) }
/>
) : null
) ) }
</div>
</PluginDocumentSettingPanel>
);
};
registerPlugin('plugin-document-students', {
render: metaboxStudents,
icon: null
});
Second solution :
PHP for my WordPress plugin :
wp_localize_script( 'wp-api', 'wpApiSettings', array(
'root' => esc_url_raw( rest_url() ),
'nonce' => wp_create_nonce( 'wp_rest' )
));
PHP for API route :
function student_api_rest() {
register_rest_route('api/v1/', 'students', array(
'methods' => 'GET',
'callback' => 'student_api_results'
));
}
function student_api_results($data) {
....
}
index.js :
import apiFetch from '#wordpress/api-fetch';
wp.apiFetch.use( apiFetch.createNonceMiddleware( wpApiSettings.nonce ) );
const [users, setUsers] = useState( null );
useEffect( () => {
wp.apiFetch( { path: '/api/v1/students' } ).then(
(result) => {
setUsers( result );
}
)
}, []);
console.log(users);
Which solution to choose and how to resolve one of those two solutions? Permission VS promise Pending
you should be able to add capabilities to the custom user types of "students". look for where the student role was activated, it should look something like this
add_role( $role, $display_name, $capabilities );
and your looking to add list_users as a capability I believe. You can find the full list of capabilities here https://wordpress.org/support/article/roles-and-capabilities/ and heres the link directly to the list_users section of that https://wordpress.org/support/article/roles-and-capabilities/#list_users
I use Ionic 3 native SQLite plugin. But below code is not working as expected. i.e. I cannot see console.log() data for the inserted data. It seems I'm doing wrong here. Can you tell me the right way?
Note: No errors. Just not working.
storeApiKeyInSqlite(key: string, name: string) {
this.sqlite.create({
name: 'MyInvoices.db',
location: 'default'
}).then((db: SQLiteObject) => {
db.executeSql('CREATE TABLE IF NOT EXISTS Apikeys(Id INT PRIMARY KEY NOT NULL, ApiKey NVARCHAR(100) NOT NULL, ApiName NVARCHAR(100) NULL)', [])
.then(() => {
db.executeSql('INSERT INTO Apikeys VALUES(NULL,?,?)', [key, name])
.then(() => {
db.executeSql('SELECT * FROM Apikeys', [])
.then(res => {
if (res.rows.length > 0) {
console.log(res.rows.item(0).Id);
console.log(res.rows.item(0).ApiKey);
console.log(res.rows.item(0).ApiName);
}
})
.catch(e => {
console.log(e);
});
}).catch(e => {
e => console.log(e)
});
}).catch(e => console.log(e));
}).catch(e => console.log(e));
}
Op's feedback:
This is the working solution for me:
storeApiKeyInSqlite(key: string, name: string) {
this.sqlite.create({
name: 'MyInvoices.db',
location: 'default'
}).then((db: SQLiteObject) => {
db.executeSql('CREATE TABLE IF NOT EXISTS Apikeys(rowid INTEGER PRIMARY KEY,ApiKey NVARCHAR(100) NOT NULL, ApiName NVARCHAR(100) NULL)', [])
.then(() => {
db.executeSql('INSERT INTO Apikeys VALUES(NULL,?,?)', [key, name])
.then(() => {
db.executeSql('SELECT * FROM Apikeys', [])
.then(res => {
if (res.rows.length > 0) {
console.log(res.rows.item(0).rowid);
console.log(res.rows.item(0).ApiKey);
console.log(res.rows.item(0).ApiName);
}
})
.catch(e => {
console.log(e);
});
}).catch(e => {
console.log(e)
});
}).catch(e => console.log(e));
}).catch(e => console.log(e));
}
Original answer:
You cant insert NULL for a PRIMARY KEY which you explicitly set as NOT NULL.
Make a query to:
db.executeSql('INSERT INTO Apikeys(ApiKey,ApiName) VALUES(?,?)', [key, name])
.then(() => {
db.executeSql('SELECT * FROM Apikeys', [])
.then(res => {
if (res.rows.length > 0) {
console.log(res.rows.item(0).Id);
console.log(res.rows.item(0).ApiKey);
console.log(res.rows.item(0).ApiName);
}
})
.catch(e => {
console.log(e);
});
}).catch(e => {
e => console.log(e)
});
For this new website I want to use async methods in NHibernate. I have this simple query using QueryOver API but I can't get this one to work with async.
It is a simple query with some where clauses that list all businesses. I want 20 of them each time I execute this.
Query:
BusinessListItem bli = null;
BusinessCategory bc = null;
Category c = null;
BusinessImage bi = null;
Image i = null;
var q = Session.QueryOver<Business>()
.JoinAlias(x => x.Categories, () => bc)
.JoinAlias(() => bc.Category, () => c)
.JoinAlias(x => x.Images, () => bi, JoinType.LeftOuterJoin)
.JoinAlias(() => bi.Image, () => i, JoinType.LeftOuterJoin)
.Where(() => bc.IsMain);
if (!string.IsNullOrEmpty(_name))
q.WhereRestrictionOn(x => x.Name).IsLike($"%{_name}%");
if (!string.IsNullOrEmpty(_streetName))
q.WhereRestrictionOn(x => x.StreetName).IsLike($"%{_streetName}%");
if (_categoryId != null)
q.Where(() => c.Id == _categoryId.Value);
if (_subCategoryIds != null)
q.WhereRestrictionOn(() => c.Id).IsIn(_subCategoryIds);
return q.Select(
Projections.Property<Business>(x => x.Id).WithAlias(() => bli.Id),
Projections.Property<Business>(x => x.Name).WithAlias(() => bli.Name),
Projections.Property("c.Name").WithAlias(() => bli.CategoryName),
Projections.Property("bi.Image").WithAlias(() => bli.Image)
)
.TransformUsing(Transformers.AliasToBean<BusinessListItem>())
.List<BusinessListItem>()
.OrderBy(x => x.Name)
.Skip(_skipCount)
.Take(20)
.ToList();
I know the method .ListAsync() exists but I cannot get it working together with the Skip, Take and OrderBy method.
Any help is much appreciated!
The solution to this question is :
var result = await q.Select(
Projections.Distinct(
Projections.Property<Business>(x => x.Id).WithAlias(() => bli.Id)
)
.TransformUsing(Transformers.AliasToBean<BusinessListItem>())
.OrderBy(x => x.Name).Asc
.Skip(_skipCount)
.Take(_takeCount)
.ListAsync<BusinessListItem>();
return result.ToList();
Thx to #DavidOsborne
Current project:
ASP.NET 4.5.1
MVC 5
I need to know if I can nest When() statements like this:
When(x => x.Cond1 == val1,
() => {
When(x => x.SubCond1 == SubVal1,
() => {
When(x => x.Final1 == finalVal1,
() => {
RuleFor(x => x.Field1)
.NotEmpty().WithMessage("Should not be empty");
// a few more here
});
When(x => x.Final2 == finalVal2,
() => {
RuleFor(x => x.Field8)
.NotEmpty().WithMessage("Should not be empty");
// a few more here
});
});
When(x => x.SubCond2 == SubVal2,
() => {
RuleFor(x => x.Field16)
.NotEmpty().WithMessage("Should not be empty");
// a few more here
});
});
Because the last thing I want is to decorate 30+ form fields like this:
RuleFor(x => x.Field1)
.NotEmpty().WithMessage("Should not be empty")
.When(x => x.Cond1 == val)
.When(x => x.SubCond1 == SubVal1)
.When(x => x.Final1 == finalVal1);
That is just untenable.
None of the conditions require validation themselves, as none of them are actually user-editable fields (just user-selectable values); I just need to compare them against known values. I would use an if/else statement if that was actually more appropriate, which it isn’t.
The model is largely flat, with only the second-level When() representing an imported model, and the third-level being different ways to handle specific fields within the imported model.
You can't, but you can try and use Rule Sets to group your rules together. Also maybe check Cascade Mode.
My question is in the title. Can you help me to implement better solution for right-to-left text direction.
For example, you can make something like this
<?php
namespace You\YourBundle\Constants;
class LanguageConstants
{
const LANGUAGE_EN = 1;
const LANGUAGE_HR = 2;
const LANGUAGE_SR = 3;
const LANGUAGE_BS = 4;
const LANGUAGE_DE = 5;
const LANGUAGE_PT = 6;
const LANGUAGE_AR = 7;
static private $constants = array(
self::LANGUAGE_EN => 'English',
self::LANGUAGE_HR => 'Hrvatski',
self::LANGUAGE_SR => 'Srpski / Српски',
self::LANGUAGE_BS => 'Bosanski / Босански',
self::LANGUAGE_DE => 'Deutsch',
self::LANGUAGE_PT => 'Português',
self::LANGUAGE_AR => 'العربية',
);
static private $constantsURL = array(
self::LANGUAGE_EN => 'en',
self::LANGUAGE_HR => 'hr',
self::LANGUAGE_SR => 'sr',
self::LANGUAGE_BS => 'bs',
self::LANGUAGE_DE => 'de',
self::LANGUAGE_PT => 'pt',
self::LANGUAGE_AR => 'ar',
);
static private $constantsRTL = array(
self::LANGUAGE_EN => false,
self::LANGUAGE_HR => false,
self::LANGUAGE_SR => false,
self::LANGUAGE_BS => false,
self::LANGUAGE_DE => false,
self::LANGUAGE_PT => false,
self::LANGUAGE_AR => true,
);
static public function getLanguageConstants()
{
natsort(self::$constants);
return self::$constants;
}
static public function getLanguageName($const)
{
return self::$constants[$const];
}
static public function getLanguageURL($const)
{
return self::$constantsURL[$const];
}
static public function getLanguageRTL($const)
{
return self::$constantsRTL[$const];
}
}
So, this is one way to go. This way you can have all your language data in one place, you can easily get en in yoururl/en/yourroute by calling getLanguageURL, and in same maner you can call getLanguageRTL in your controller with a proper _local and pass in to twig so that you could do if R2L true then dir=rtl.
You can even make a twig extension to call getLanguageRTL from twig but since controller is the place to do all "dirty works", why bother.
Best regards