Skip to content

Commit 3d25c41

Browse files
committed
Update just the url hash from a component instead of a complete redirect.
1 parent 5611f23 commit 3d25c41

File tree

6 files changed

+57
-10
lines changed

6 files changed

+57
-10
lines changed

django_unicorn/components.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,18 @@
3232

3333
class UnicornField:
3434
"""
35-
Can be used to provide a way to serialize a class quickly.
36-
Probably not a good idea in lots of cases.
35+
Base class to provide a way to serialize a component field quickly.
3736
"""
3837

3938
def to_json(self):
4039
return self.__dict__
4140

4241

42+
class HashUpdate:
43+
def __init__(self, hash):
44+
self.hash = hash
45+
46+
4347
class ComponentLoadError(Exception):
4448
pass
4549

django_unicorn/static/js/messageSender.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,16 @@ export function send(component, callback) {
5959

6060
// Redirect to the specified url if it is set
6161
// TODO: For turbolinks support look at https://github.com/livewire/livewire/blob/f2ba1977d73429911f81b3f6363ee8f8fea5abff/js/component/index.js#L330-L336
62-
if (responseJson.redirect && responseJson.redirect.url) {
63-
component.window.location.href = responseJson.redirect.url;
62+
if (responseJson.redirect) {
63+
if (responseJson.redirect.url) {
64+
// TODO: Use config to potentially use `component.window.history.pushState()`
65+
component.window.location.href = responseJson.redirect.url;
6466

65-
if (isFunction(callback)) {
66-
callback([], null, null);
67+
if (isFunction(callback)) {
68+
callback([], null, null);
69+
}
70+
} else if (responseJson.redirect.hash) {
71+
component.window.location.hash = responseJson.redirect.hash;
6772
}
6873
}
6974

django_unicorn/views.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import orjson
1212

1313
from .call_method_parser import InvalidKwarg, parse_call_method_name, parse_kwarg
14-
from .components import UnicornField, UnicornView
14+
from .components import HashUpdate, UnicornField, UnicornView
1515
from .errors import UnicornViewError
1616
from .serializer import dumps
1717
from .utils import generate_checksum
@@ -386,11 +386,18 @@ def message(request: HttpRequest, component_name: str = None) -> JsonResponse:
386386
return_data = {}
387387
redirect_data = {}
388388

389+
# TODO: Support a tuple/list return_value which could contain a redirect and value(s).
390+
# `return (redirect(...), 1)` -> { return: { 1 } }, redirect: { url: "..." } }
391+
# easier for `HashUpdate`, would need to handle setting last return value after new component loaded
389392
if return_value is not None:
390393
if isinstance(return_value, HttpResponseRedirect):
391394
redirect_data = {
392395
"url": return_value.url,
393396
}
397+
elif isinstance(return_value, HashUpdate):
398+
redirect_data = {
399+
"hash": return_value.hash,
400+
}
394401
else:
395402
try:
396403
return_data = orjson.loads(dumps(return_value))

example/unicorn/components/models.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from coffee.models import Flavor
55

6-
from django_unicorn.components import UnicornView
6+
from django_unicorn.components import HashUpdate, UnicornView
77
from django_unicorn.db import DbModel
88
from django_unicorn.decorators import db_model
99

@@ -30,13 +30,18 @@ def hydrate(self):
3030

3131
def add_instance_flavor(self):
3232
self.instance_flavor.save()
33+
id = self.instance_flavor.id
34+
self.reset()
3335

34-
return redirect(f"/models?createdId={self.instance_flavor.id}")
36+
return HashUpdate(f"#createdId={id}")
3537

3638
def add_class_flavor(self):
3739
self.class_flavor.save()
40+
id = self.class_flavor.id
3841
self.reset()
3942

43+
return redirect(f"/models?createdId={id}")
44+
4045
@db_model
4146
def delete(self, model):
4247
model.delete()

tests/views/fake_components.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from django import forms
44
from django.shortcuts import redirect
55

6-
from django_unicorn.components import UnicornView
6+
from django_unicorn.components import HashUpdate, UnicornView
77
from example.coffee.models import Flavor
88

99

@@ -28,6 +28,9 @@ def test_method_string_param(self, param):
2828
def test_redirect(self):
2929
return redirect("/something-here")
3030

31+
def test_hash_update(self):
32+
return HashUpdate("#test=1")
33+
3134
def test_return_value(self):
3235
return "booya"
3336

tests/views/message/test_call_method.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,29 @@ def test_message_call_method_redirect(client):
4444
assert body["redirect"].get("url") == "/something-here"
4545

4646

47+
def test_message_call_method_hash_update(client):
48+
data = {}
49+
message = {
50+
"actionQueue": [
51+
{"payload": {"name": "test_hash_update"}, "type": "callMethod",}
52+
],
53+
"data": data,
54+
"checksum": generate_checksum(orjson.dumps(data)),
55+
"id": "FDHcbzGf",
56+
}
57+
58+
response = client.post(
59+
"/message/tests.views.fake_components.FakeComponent",
60+
message,
61+
content_type="application/json",
62+
)
63+
64+
body = orjson.loads(response.content)
65+
66+
assert "redirect" in body
67+
assert body["redirect"].get("hash") == "#test=1"
68+
69+
4770
def test_message_call_method_return_value(client):
4871
data = {}
4972
message = {

0 commit comments

Comments
 (0)