Fetch public todos - subscription
Lets setup ports to subscribe to public todo data and fetch the initial list of public todo list the user will see after successful login.
Open src/Main.elm
and add the following code:
port createSubscriptionToOnlineUsers : ( String, String ) -> Cmd msgport gotOnlineUsers : (Decode.Value -> msg) -> Sub msg+port createSubscriptionToPublicTodos : ( String, String ) -> Cmd msg++port gotRecentPublicTodoItem : (Decode.Value -> msg) -> Sub msg
We are creating two more ports to query latest public todo.
Construct GraphQL Subscription
onlineUsersSelection : SelectionSet OnlineUser Hasura.Object.Online_usersonlineUsersSelection =SelectionSet.map2 OnlineUserOnlineUser.id(OnlineUser.user selectUser)+publicTodoListSubscriptionOptionalArgument : TodosOptionalArguments -> TodosOptionalArguments+publicTodoListSubscriptionOptionalArgument optionalArgs =+ { optionalArgs | where_ = whereIsPublic True, order_by = orderByCreatedAt Desc, limit = OptionalArgument.Present 1 }+++publicListSubscription : SelectionSet Todos RootSubscription+publicListSubscription =+ Subscription.todos publicTodoListSubscriptionOptionalArgument todoListSelection+publicTodoListQueryLimit : Int -> OptionalArgument Int+publicTodoListQueryLimit limit =+ Present limit+++lteLastTodoId : Int -> OptionalArgument Int_comparison_exp+lteLastTodoId id =+ Present+ (buildInt_comparison_exp+ (\args ->+ { args+ | lte_ = Present id+ }+ )+ )+++publicTodoListOffsetWhere : Int -> OptionalArgument Todos_bool_exp+publicTodoListOffsetWhere id =+ Present+ (buildTodos_bool_exp+ (\args ->+ { args+ | id = lteLastTodoId id+ , is_public = equalToBoolean True+ }+ )+ )+++publicTodoListQueryOptionalArgs : Int -> Int -> TodosOptionalArguments -> TodosOptionalArguments+publicTodoListQueryOptionalArgs id limit optionalArgs =+ { optionalArgs | where_ = publicTodoListOffsetWhere id, order_by = orderByCreatedAt Desc, limit = publicTodoListQueryLimit limit }+++todoListSelectionWithUser : SelectionSet Todo Hasura.Object.Todos+todoListSelectionWithUser =+ SelectionSet.map5 Todo+ Todos.id+ Todos.user_id+ Todos.is_completed+ Todos.title+ (Todos.user selectUser)+++loadPublicTodoList : Int -> SelectionSet Todos RootQuery+loadPublicTodoList id =+ Query.todos (publicTodoListQueryOptionalArgs id 7) todoListSelectionWithUser+++makeRequest : SelectionSet Todos RootQuery -> String -> Cmd Msg+makeRequest query authToken =+ makeGraphQLQuery+ authToken+ query+ (RemoteData.fromResult >> FetchPublicDataSuccess)
Add/Update Data Types
type alias OnlineUsersData =RemoteData Decode.Error OnlineUsers+type alias PublicDataFetched =+ RemoteData (Graphql.Http.Error Todos) Todosinitialize : Modelinitialize ={ privateData = initializePrivateTodo, online_users = RemoteData.NotAsked, publicTodoInsert = ""- , publicTodoInfo = PublicTodoData getPublicTodos 0 1 0 True+ , publicTodoInfo = PublicTodoData [] 0 0 0 True, authData = AuthData "" "" "" "", authForm = AuthForm Login False False ""}getInitialEvent : String -> Cmd MsggetInitialEvent authToken =Cmd.batch[ fetchPrivateTodos authToken+ , createSubscriptionToPublicTodos ( publicListSubscription |> Graphql.Document.serializeSubscription, authToken ), createSubscriptionToOnlineUsers ( onlineUsersSubscription |> Graphql.Document.serializeSubscription, authToken )]subscriptions : Model -> Sub Msgsubscriptions model =case String.length model.authData.authToken of0 ->Sub.none_ ->Sub.batch+ [ gotRecentPublicTodoItem RecentPublicTodoReceived, gotOnlineUsers GotOnlineUsers, Time.every 30000 Tick]+updatePublicTodoData : (PublicTodoData -> PublicTodoData) -> Model -> Cmd Msg -> ( Model, Cmd Msg )+updatePublicTodoData transform model cmd =+ ( { model | publicTodoInfo = transform model.publicTodoInfo }, cmd )
Add new Msg type
type Msg= EnteredEmail String| EnteredPassword String| EnteredUsername String| MakeLoginRequest| MakeSignupRequest| ToggleAuthForm DisplayForm| GotLoginResponse LoginResponseParser| GotSignupResponse SignupResponseParser| ClearAuthToken| FetchPrivateDataSuccess TodoData| InsertPrivateTodo| UpdateNewTodo String| InsertPrivateTodoResponse (GraphQLResponse MaybeMutationResponse)| MarkCompleted Int Bool| UpdateTodo UpdateTodoItemResponse| DelTodo Int| TodoDeleted DeleteTodo| AllCompletedItemsDeleted AllDeleted| DeleteAllCompletedItems| Tick Time.Posix| UpdateLastSeen UpdateLastSeenResponse| GotOnlineUsers Decode.Value+ | RecentPublicTodoReceived Decode.Value+ | FetchPublicDataSuccess PublicDataFetched
Handle new Msg types in update
-- Imports --+import Array-- Update --UpdateLastSeen _ ->( model, Cmd.none)GotOnlineUsers data ->letremoteData =Decode.decodeValue (onlineUsersSubscription |> Graphql.Document.decoder) data |> RemoteData.fromResultin( { model | online_users = remoteData }, Cmd.none )+ RecentPublicTodoReceived data ->+ let+ remoteData =+ Decode.decodeValue (publicListSubscription |> Graphql.Document.decoder) data |> RemoteData.fromResult+ in+ case remoteData of+ RemoteData.Success recentData ->+ case List.length recentData > 0 of+ True ->+ case Array.get 0 (Array.fromList recentData) of+ Just recDat ->+ case model.publicTodoInfo.oldestTodoId of+ 0 ->+ let+ queryObj =+ loadPublicTodoList recDat.id+ in+ updatePublicTodoData (\publicTodoInfo -> { publicTodoInfo | currentLastTodoId = recDat.id }) model (makeRequest queryObj model.authData.authToken)+ _ ->+ let+ updatedNewTodoCount =+ model.publicTodoInfo.newTodoCount + 1+ in+ case model.publicTodoInfo.currentLastTodoId >= recDat.id of+ True ->+ ( model, Cmd.none )+ False ->+ updatePublicTodoData (\publicTodoInfo -> { publicTodoInfo | newTodoCount = updatedNewTodoCount }) model Cmd.none+ Nothing ->+ ( model, Cmd.none )+ False ->+ ( model, Cmd.none )+ _ ->+ ( model, Cmd.none )+ FetchPublicDataSuccess response ->+ case response of+ RemoteData.Success successData ->+ case List.length successData of+ 0 ->+ ( model, Cmd.none )++ _ ->+ let+ oldestTodo =+ Array.get 0 (Array.fromList (List.foldl (::) [] successData))+ in+ case oldestTodo of+ Just item ->+ updatePublicTodoData (\publicTodoInfo -> { publicTodoInfo | todos = successData, oldestTodoId = item.id }) model Cmd.none++ Nothing ->+ ( model, Cmd.none )++ _ ->+ ( model, Cmd.none )
Now subscribe to the most recent todo over ports
Open src/Main.elm
and add the following code:
document.addEventListener("DOMContentLoaded", function() {var app = Elm.Main.init({node: document.getElementById("root")});+ app.ports.createSubscriptionToPublicTodos.subscribe(function(data) {+ /* Initiate subscription request */+ var [ data, authToken ] = data;+ if (authToken.length > 0) {+ // app.ports.creatingSubscriptionToTasks.send(1);+ getClient(authToken).subscribe({+ query: gql`${data}`,+ variables: {}+ }).subscribe({+ next(resp) {+ app.ports.gotRecentPublicTodoItem.send(resp);+ },+ error(err) {+ console.log('error is');+ console.log(err);+ }+ });+ }+ });})
Remove dummy values
- seedIds : List Int- seedIds =- [ 1, 2 ]--- publicSeedIds : List Int- publicSeedIds =- [ 1, 2, 3, 4 ]--- todoPublicPlaceholder : String- todoPublicPlaceholder =- "This is public todo"--- generateUser : Int -> User- generateUser id =- User ("someUser" ++ String.fromInt id)--- generatePublicTodo : String -> Int -> Todo- generatePublicTodo placeholder id =- Todo id ("User" ++ String.fromInt id) False (placeholder ++ " " ++ String.fromInt id) (generateUser id)--- getPublicTodos : Todos- getPublicTodos =- List.map (generatePublicTodo todoPublicPlaceholder) publicSeedIds
Awesome! You have successfully subscribed to new public todos.
Did you find this page helpful?
Start with GraphQL on Hasura for Free
- Build apps and APIs 10x faster
- Built-in authorization and caching
- 8x more performant than hand-rolled APIs