Code Monkey home page Code Monkey logo

Comments (22)

TehShrike avatar TehShrike commented on June 3, 2024 1

I'm turning around on this idea – I think there are good use cases for reloading some of the current states, and while talking to @saibotsivad the other day, I thought of a way to implement it.

State changes are driven by the browser's location right now, and the go method works by changing the location, and trusting that to trigger the state change.

I don't want to mess with that paradigm, so I wouldn't tie this reload-without-a-location-change functionality to go().

But maybe there should be a new reload or refresh (give name ideas plz) method that takes a list of parameters, and causes all states to be reloaded as if that parameter had changed. e.g. if you know that the company object you were viewing had changed and you wanted to reload all the views that would be affected by that change, you would call stateRouter.actAsThoughThisChanged([ 'companyId' ]).

Thoughts?

from abstract-state-router.

daytonlowell avatar daytonlowell commented on June 3, 2024 1

As far as naming goes, there is precedence for reload on the web (see document.location.reload()).

from abstract-state-router.

daytonlowell avatar daytonlowell commented on June 3, 2024 1

I currently use a mediator for this concept.

So in this example, the app.schoolId.teams.list.published state would do something like mediator.publish('school-change', school) and all the states that care about school would catch the change mediator.provide('school-change', school => domApi.set({ school }))

from abstract-state-router.

TehShrike avatar TehShrike commented on June 3, 2024

What's your use case?

In general, anything that should cause your states to reload should be represented in the route.

I'd need to know more about your specific use case to give better advice.

What is changing that makes you want to re-run all the resolves (I assume that's the motivation)?

from abstract-state-router.

felipedrumond avatar felipedrumond commented on June 3, 2024

The idea is to enter the route and reload the specified template even though the user is already in that route.

from abstract-state-router.

TehShrike avatar TehShrike commented on June 3, 2024

Right, I got that, but why? What is happening in your application that makes that a thing you want to do?

from abstract-state-router.

felipedrumond avatar felipedrumond commented on June 3, 2024

Allow users to reload the template by navigating to the same url address. In Angular we can either set the route to not be reused or configure a behaviour to onSameUrlNavigation.

from abstract-state-router.

TehShrike avatar TehShrike commented on June 3, 2024

Why do you want users to be able to reload the page? What is going on that makes a reload a good idea? Is it something in a resolve function that you want to happen again?

from abstract-state-router.

felipedrumond avatar felipedrumond commented on June 3, 2024

I want them to restart the component without having a 'restart button'. Not sure this is achievable by configuring the states or resolves.

from abstract-state-router.

TehShrike avatar TehShrike commented on June 3, 2024

Why do you want them to restart the component? What is your app doing? Why does the component need to be restarted?

from abstract-state-router.

TehShrike avatar TehShrike commented on June 3, 2024

This is inevitably tied to your specific application needs - I would really recommend joining the chat and chatting with other ASR users about how you should accomplish what you need

from abstract-state-router.

saibotsivad avatar saibotsivad commented on June 3, 2024

Suppose that I'm at a state like app.schoolId.teams.list.published and something I do changes the school object which is loaded in the resolve of app.schoolId.

I think I would like to be able to re-run the resolve etc. functions of app.schoolId on up the tree, instead of e.g. re-running all the resolve functions.

However, if it re-ran all the resolves etc., that would still be okay, the asr user (me!) would be able to implement some server or browser side caching, to make sure the reloading didn't take too long.

from abstract-state-router.

saibotsivad avatar saibotsivad commented on June 3, 2024

That's essentially what I'm starting to work toward as well.

Getting it started has felt kind of clunky, but it's pretty clear that after I make a handful, some obvious tooling will present itself that will make it cleaner and easier.

from abstract-state-router.

daytonlowell avatar daytonlowell commented on June 3, 2024

Unfortunately, newer versions of mannish don't support the concept of multiple providers handling the same named function. Thus, I'm still on an older version.

from abstract-state-router.

saibotsivad avatar saibotsivad commented on June 3, 2024

I started developing my tooling for this using this emitter.

There's a little work with making sure to unsubscribe the emitter when a component is destroyed, etc., but it's been pretty good so far. 🤞

from abstract-state-router.

TehShrike avatar TehShrike commented on June 3, 2024

I think I would like to be able to re-run the resolve etc. functions of app.schoolId on up the tree, instead of e.g. re-running all the resolve functions.

@saibotsivad that's what I'm aiming for – presumably, that state depends on a schoolId parameter, so if you called stateRouter.actAsThoughThisChanged([ 'schoolId' ]), ASR should only re-resolve/render the states that would have been re-run if you changed the schoolId in the url.

from abstract-state-router.

TehShrike avatar TehShrike commented on June 3, 2024

I'm feeling pretty good about this feature so far. We can keep workshopping the name. In the meantime, if anyone wanted to write a unit test or two, I'd much appreciate it.

A test could start with a copy/paste from https://github.com/TehShrike/abstract-state-router/blob/master/test/test.js changed to assert:

  1. beforeResetState should be emitted for every state that should be getting reset (if schoolId changed at app.school.whatevs, then app.school and app.school.whatevs should be reset)
  2. resolve and activate should be called for each of those functions

You can use whatever dummy method name you like for now in the tests.

from abstract-state-router.

sw-clough avatar sw-clough commented on June 3, 2024

I am in need of this functionality. As an example of what I am trying to do, I have route foo that shows the title and has tabs for the child states. The default child is foo.view, which shows some other info, and foo.edit. Upon doing an edit, which might change the title, I need to reload the foo route, to see the new title.

TBH, I would be happy if I could just do something like go("foo", {}, {force: true}). Right now, this refreshes foo.view, but does not refresh foo. Would this be quicker and easier to implement?

from abstract-state-router.

TehShrike avatar TehShrike commented on June 3, 2024

@sw-clough that's a good use case to note – where you are actually doing a state change, but you need a parent of the changed state to reload as well. It would be good to support that too.

In your case, is foo dependent on a particular parameter to load the title of the thing?

Can you give your concrete example instead of using foo?

I don't want to do a quick/easy implementation – I'm pretty sure this functionality can be implemented in a way that fits in nice with the current ASR paradigms, where we just say "this is the browser navigation that should happen, and also for the purpose of state changes, these parameters should be treated as if they had changed as well".

from abstract-state-router.

saibotsivad avatar saibotsivad commented on June 3, 2024

@sw-clough This might not work for you, but I'll show you one of the ways that I manage updates. I leave it here in hopes that it helps you, or someone else.

In my application, I create a global emitter:

// emitter.js
const createEmitter = require('better-emitter')
const emitter = createEmitter()
module.exports = emitter

Then in the child view, e.g. foo.view, when the object changes I emit that change:

// foo-view.js
const emitter = require('./emitter.js')
//...
asr.addState({
    name: 'foo.view',
    activate: ({ domApi }) => {
        domApi.on('change', title => {
            emitter.emit('change-title', title)
        })
    }
})

And in any view that cares about that property, I watch for those changes (be careful to not leave event emitter listeners lying around):

// foo.js
const emitter = require('./emitter.js')
//...
asr.addState({
    name: 'foo',
    activate: ({ domApi }) => {
        const unsubscribe = emitter.on('change-title', title => {
            domApi.set({ title })
        })
        domApi.on('destroy', () => {
            if (unsubscribe) {
                unsubscribe()
            }
        })
    }
})

In practice, I've made some wrapper functions so I can register a component for changes, and handle the subscribe/unsubscribe functionality without a lot of repeated code.

There may be easier ways to manage state inside your framework (for example "stores" in Svelte3), but something along these lines:

// state.js
const emitter = require('./emitter.js')
module.exports = {
    subscribe: (domApi, key, cb) => {
        const unsubscribe = emitter.on(key, props => {
            cb(props)
        })
        domApi.on('destroy', () => {
            if (unsubscribe) {
                unsubscribe()
            }
        })
    }
}

And then in the watching state:

// foo.js
const { subscribe } = require('./state.js')
//...
asr.addState({
    name: 'foo',
    activate: ({ domApi }) => {
        subscribe(domApi, 'change-title', title => domApi.set({ title }))
    }
})

from abstract-state-router.

daytonlowell avatar daytonlowell commented on June 3, 2024

A .reload method makes sense to me. That said, I do agree with @sw-clough that a force-like option you could pass to .go would be pretty handy. Without that, my code would have to figure out if I need to call .go or .reload in certain instances, which would involve looking at the current state name and the parameters and comparing them to the "destination" state to see if they're different. That's a lot of overhead that I'd rather the state router abstract away from me.

Here's an example use case for me:
I have a search view. The parent state has form input controls where they can create a search query. The child state is the results. The results state takes parameters that are passed from the parent.

The user can perform certain operations on the results that might change which results should be shown. Also the user could leave the results open for days and decide to reperform the search when they return(data could have changed on the server). Currently to do this, they have to either go to a different state and return, or refresh the browser(entire web app), neither of which is a great solution.

My current workaround is to make a parameter be a uuid and generate a new one on each .go call for this state.

from abstract-state-router.

TehShrike avatar TehShrike commented on June 3, 2024

That argument for baking it into go makes sense to me.

You would only want the results state to be reloaded in that case, right? You wouldn't want every parent state to reload and re-render?

I'm imagining that rather than a boolean, go could take another option that would be an array of property names about which you wanted to say "act as if all of these parameters changed in the url, even if they're actually the same value".

You could pass in the names of all of the parameters that are relevant to the search results, and the search results would always be refreshed even if the values hadn't changed.

Alternately, if you only wanted the results state to reload when you're at app.search.results, you could pass in a parameter like app.search to say "reload all descendants of this state, even if their parameters haven't changed".

This might be easier/nicer in some circumstances, but I don't feel as good about it, because it kind of steps around the "the parameters drive the states" model.

from abstract-state-router.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.