This course is no longer maintained and may be out-of-date. While it remains available for reference, its content may not reflect the latest updates, best practices, or supported features.
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

