When to use dispatch with alt.js flux - flux

I'm new to using flux and have started using the alt.js implmentation. I'm wondering when I would use dispatch from within my actions. For example, take this code.
//ImageActions.js
class ImageActions {
getImages(id) {
return Api.get(`topics/${id}`).then(response => {
let images = response.data.filter(image => {
return !image.is_album;
});
this.updateImages(images);
});
}
updateImages(images) {
return images;
}
}
---------------------------------------------------
//ImageStore.js
class ImageStore {
constructor() {
this.images = [];
this.image = {};
this.bindListeners({
handleUpdateImages: ImageActions.UPDATE_IMAGES
});
}
handleUpdateImages(images) {
this.images = images;
}
}
Currently this works without using the dispatch() function as seen in their tutorial here http://alt.js.org/guide/async/
I'm wondering when I'd want to do this and what dispatch does and what it does differently than just returning the value from the updateImages function in ImageaActions.js

You use dispatch when your async calls resolve. In this case it works because when your sync call finishes, you are calling another action (updateImages) which is triggering the dispatch, since getImages is not triggering a dispatch. Remember the return of an async call is a Promise.

Related

Sinon with complex object structure

I'm using #types/xrm and attempting to test a method call with sinon. Unfortunately I am hitting quite a few issues due to the complex nature of the return and call I need to mock. I can find really simple examples of sinon stubbing or spying on calls, but nothing more complex than that.
I have the following simple code:
export class AccountForm {
static Fields = class {
static PrimaryContact = "primarycontactid";
static Name = "name";
}
public onLoad(context: Xrm.Events.EventContext): void {
// Get the form context
const formContext = context.getFormContext();
// Get the attributes required
const primaryContact = formContext.getAttribute(AccountForm.Fields.PrimaryContact);
const name = formContext.getAttribute(AccountForm.Fields.Name);
// Add our onchange events
primaryContact.addOnChange(this.onChangePrimaryContact);
name.addOnChange(this.onChangeName);
}
public async onChangePrimaryContact(context: Xrm.Events.EventContext): Promise<void> {
alert("Do something");
}
public async onChangeName(context: Xrm.Events.EventContext): Promise<void> {
alert("Do something else");
}
}
I want to test that an onchange event has been registered to both fields. Ideally, I'd like to check it's the RIGHT onchange, but I'll settle with the fact that it's been called once.
The "easy" way has been to check that the addOnChange method was called twice, this is as below:
import {AttributeMock, XrmMockGenerator} from "xrm-mock";
import * as sinon from "sinon";
import { AccountForm } from "../../src/entities/Account/Form";
describe("Account Form Tests", () => {
describe("Check Onload", () => {
beforeEach(() => {
XrmMockGenerator.initialise();
XrmMockGenerator.Attribute.createString("name", "");
XrmMockGenerator.Attribute.createLookup("primarycontactid", []);
});
it("should register onChange functions", () => {
// Arrange
let formContext = XrmMockGenerator.getFormContext();
let context = XrmMockGenerator.getEventContext();
// Stub
const attributeStub = sinon.stub(AttributeMock.prototype, "addOnChange");
// Act
let form = new AccountForm();
form.onLoad(context);
// Assert
expect(attributeStub.calledTwice).toBeTruthy();
});
});
});
But this is not very resilient, as it is not checking WHICH attributes the onChange functions were added to, or what function was registered.
I've tried stubbing the ForContext's "GetAttribute", but looks like it's requiring me to mock the entire return object, as otherwise, the stub does not return anything? I can get around this with using spy, but still can't work out how to check the attribute that the onChange is being added to and what the function is
Am I missing something obvious here?

Cannot call method - mocha

I am running some test in my first smart contract called Inbox.sol.
I want to call the method .message in order to see if it is equal to the default variable I use when I deploy the contract with web3.
My Inbox.sol code
pragma solidity >=0.6.12;
contract Inbox {
string public message;
function initialInbox(string memory initialMessage) public {
message = initialMessage;
}
function setMessage(string memory newMessage) public {
message = newMessage;
}
}
My test file with Mocha is:
let accounts
let inbox
beforeEach(async () => {
// Get a list of all accounts
accounts = await web3.eth.getAccounts()
// Use one of those account to deploy the contract
inbox = await new web3.eth.Contract(abi)
.deploy({ data: bytecode, arguments: [INITIAL_ARGUMENT]})
.send({ from: accounts[0], gas: GAS})
})
describe(('Inbox'), () => {
it("has a default message", async () => {
const message = await inbox.methods.message() // Returns a big object
console.log(message)
const messageCalled = await inbox.methods.message().call()
console.log(messageCalled) // Returns nothing
assert.strictEqual(message, INITIAL_ARGUMENT)
})
})
Your JS inbox variable is an instance of web3.eth.Contract (docs).
The inbox.methods.message() is an instance of a helper object (that's the "Returns a big object" in your comment) containing the .call() method, that you need to use when you want to perform a read-only call.
const message = await inbox.methods.message().call() // Returns the string
Docs: https://web3js.readthedocs.io/en/v1.3.4/web3-eth-contract.html#methods-mymethod-call
Change your code and add a contractor.
function constructor(string memory initialMessage) public {
message = initialMessage;
}
if you are using an older version of solidity for example ^0.4.17. you can create a constructor by create a method same name as your contract class.
function Inbox(string memory initialMessage) public {
message = initialMessage;
}

How to subscribe new value in Akavache?

I'm using Akavache's GetAndFetchLatest method and I have created dependency services to communicate with Akavache's method. I'm calling akavache from service layer successfully when i directly reference. For subscribing
MyMod result = null;
var cache = BlobCache.LocalMachine;
var cachedPostsPromise = cache.GetAndFetchLatest(
"mykey",
() => GetInfo(),
offset =>
{
//some condition
});
cachedPostsPromise.Subscribe(subscribedPosts => {
Device.BeginInvokeOnMainThread(() =>
{
//do sothing.
});
});
result = await cachedPostsPromise.FirstOrDefaultAsync();
return result;
It works.But how an I call subscribe on service layer with interface/dependency service?
I think you are new to reactive programming. Understanding the basic principles helps when using Akavache. Maybe this intro helps.
To answer your question, place code like this in your "repository" class:
public override IObservable<MyClass> Get(string key)
{
var cachedObservable = blobCache.GetAndFetchLatest<MyClass>(key,
() => GetFromServerAsync(key));
return cachedObservable ;
}
And in the caller:
private void getNewData()
{
var myClassObservable = myRepository.Get("the key");
myClassObservable.Subscribe(handleNewMyClass);
}
private void handleNewMyClass(MyClass newClass)
{
//handle the new class
}
Note that handleNewMyClass() is called twice:
first with the MyClass from cache
then with the MyClass that was fetched (from the server)
Using this approach you can simply place the repository class in your IoC Container.
Please find the the sample code :
var result = BlobCache.LocalMachine;
var cachedPostsPromise = cache.GetAndFetchLatest(
"mykey",
() => ViewModelLocator.GetInstance<IYourServiceName>().MethodName(),
offset =>
{
//some condition
});
cachedPostsPromise.Subscribe(subscribedPosts => {
Device.BeginInvokeOnMainThread(() =>
{
//Your piece of code
});
});
result = await cachedPostsPromise.FirstOrDefaultAsync();
return result;
Please note the there any anything inside subscribed will be called twice : first set of data will be cache and second set will be freshly fetched from server.You have to manage according.

Is a good practice to request db data on controller when using ORM?

When using ORMs is it a good practice do things like model-instance.findAll() on a controllers?
Yes, using the Sequelize ORM in a controller would be considered good practice, assuming it is implemented correctly - error handling, etc.
Example:
// `models` should contain model definitions
function MyController(app) {
const controller = this;
controller.getRecord = async (id, options) => {
try {
const records = await models.ModelName.findById(
where: {
id,
},
});
// do more things
return records;
} catch (err) {
// handle the error
return err;
}
};
return controller;
}
module.exports = MyController;

Closing an async Response

I'm trying to close the current response but nothing happens when I try HttpContext.Response.Body.Close() and Response.End() does not exist.
The reason I'm trying to achieve this is because of legacy validator functions that write an error and close the response, or at least stopping the parent WebAPI method.
Example:
private async Task Register_v2()
{
//Read JSON to object
UserRegisterRequest userRegisterRequest = Request.ReadBody().FromJson<UserRegisterRequest>();
//Validate object (legacy static method with a lot of logic)
//Validate() should end the response if object not validated
userRegisterRequest.Validate(isJson: true, isThrowHttpError: true);
//Code still reaches here and request does not close
string test = "hey I'm alive";
}
Can I workaround this with middleware somehow?
Thanks
There are two ways to terminate the Request pipeline.
Use app.Run in Startup.Configure
Do not invoke _next(context) in Middleware.InvokeAsync
For your scenario, you could try second option by determining whether to invoke _next(context).
public class FirstMiddleware
{
private readonly RequestDelegate _next;
public FirstMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
await context.Response.WriteAsync($"This is { GetType().Name }");
//decide whether to invoke line below based on your business logic
//await _next(context);
bool isValid = userRegisterRequest.Validate(isJson: true, isThrowHttpError: true);
//change userRegisterRequest.Validate to reutrn whether the model is valid
if(!isValid)
{
await context.Response.WriteAsync($"Model is not valid");
}
else
{
await _next(context);
}
}
}

Resources