I have an app where a user can create projects. The currentProject in the model is a Maybe Project type with the initial value set to Nothing (since there may be no projects created yet by that user).
type alias Project =
{ name : String }
type alias Model =
{ user : User
, currentProject : Maybe Project
}
This is in the init for the Model:
currentProject = Nothing
I then have a dropdown where the user can select a project. Upon selecting it the onClick calls the following update:
type Msg
= ...
| SetProject Project
The update function that I try to run looks like this:
SetProject project ->
case project of
Just project ->
( { model | currentProject = project }, Cmd.none )
Nothing ->
( model, Cmd.none )
I get an error because project is of type Project and not Maybe Project.
I know the project exists because it's coming from an existing list of projects in the app. But, I cannot set currentProject to type Project because I need to initialize the Model with Nothing.
So, how can I update the Maybe Project record with type Project?
Use the Just constructor:
SetProject project ->
( { model | currentProject = Just project }, Cmd.none )
Your message says you are expecting a Project type, but then you are pattern matching on it to check to see if it is a (Maybe Project) but it isn't. So, either pass in a Maybe Project in your msg or change your update function to be this.
SetProject project ->
( { model | currentProject = Just project }, Cmd.none )
Related
I have a similar code like below. But since the logics are same for my other projects I wanted to keep this in a single file and "apply" in every project. So I tried using the "apply" command, but it won't work. Nothing complaining about the build but my logic is not executing in the build process.
Question - Why?
lateinit var projectConfigurer: (ProjectDescriptor, ProjectDescriptor) -> Unit
projectConfigurer = { _, project ->
project.name = project.name.replace("/", "-")
// Some logic to validate project naming convention
project.children.forEach { child ->
projectConfigurer(project, child)
}
}
rootProject.children.forEach { project ->
projectConfigurer(rootProject, project)
}
Here is what I wanted to do.
apply(from = "common/common.settings.gradle.kts")
And all the code I needed to move to "common.settings.gradle.kts", which was in a common folder reletive to "settings.gradle.kts"
I'm building an application in Elm where most API calls are protected; i.e. the user needs to be logged in for the API call to work. If the user is not logged in, they will receive a 401 Unauthorized response. I want the application to redirect to the login page if any response is a 401.
Currently, I only have this redirect set up for a single API call. Here is a stripped-down version of the code to give an idea of how it's set up:
-- Util/Api.elm
type alias Data data =
{ data : data
}
-- Resources/Expense.elm
getExpenses : (Progress (Api.Data (List Expense)) -> msg) -> Sub msg
getExpenses msg =
(dataDecoder expenseListDecoder)
|> Http.get expensesEndpoint
|> Progress.track expensesEndpoint msg
-- Main/Msg.elm
type Msg
= ExpenseListMsg ExpenseListMsg
| RedirectToLogin
-- Main/Update.elm
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
ExpenseListMsg msg ->
ExpenseList.Update.update msg model
GoTo path ->
model ! [ Navigation.newUrl path ]
RedirectToLogin ->
model ! [ Navigation.load "path/to/login" ]
-- ExpenseList/Msg.elm
type ExpenseListMsg
= GetExpensesProgress (Progress (Api.Data (List Expense)))
| SetLoading
-- ExpenseList/Update.elm
update : ExpenseListMsg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
SetLoading ->
{ model | expenses = setExpensesLoading model.expenses } ! []
GetExpensesProgress (Done { data }) ->
{ model | expenses = addExpenses model.expenses data } ! []
GetExpensesProgress (Fail (BadStatus { status })) ->
case status.code of
401 ->
model ! [ msgToCmd RedirectToLogin ]
_ ->
model ! []
GetExpensesProgress (Fail error) ->
model ! []
GetExpensesProgress progress ->
{ model | expenses = setExpensesLoading model.expenses } ! []
Essentially, I want to move the logic around 401 responses from ExpenseList/Update.elm up to Main/Update.elm so that I can use it for any request I want.
I attempted a number of things, but nothing quite worked with Elm's type system. For example, one thing I wanted to do was try to do a nested pattern match with missing specificity in the middle, e.g.:
-- Main/Update.elm
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
ApiCall (messageType (msg (Fail (BadStatus { status })))) ->
case status of ->
. . .
. . .
I was hoping something like this would work and would match a message that looked like: ApiCall (ExpenseListMsg (GetExpensesProgress (Fail (BadStatus)))). Unfortunately, it's not proper Elm syntax, so my code didn't compile.
How can I write something that will allow me to mark an API call as protected and catch 401 errors at the top level in Main.Update.update?
Currently, the API call is encapsulated by the ExpenseList/Update module. This encapsulation is what makes the API call results unavailable to the Main module. The interaction works like this: Main -> FeatureModule -> API
Because the API is what provides the information needed to determine whether the app should redirect to the login page, and you want the Main module to perform the redirect, the Main module needs access to the API. Hence, the encapsulation needs to go. Instead, you can:
Have an API module which provides the low-level API functionality by producing Tasks. Unlike producing Cmds, this allows the caller, such as the Main module to decide how to handle the result of the Task, which can be acquired by converting the Task to a Cmd and giving it to the Elm runtime for execution.
Have the ExpenseList.Update module use the API module to create Tasks.
With this arrangement:
The Main module sends high-level commands to a feature module, which then uses the API module to produce the low-level instructions, which are then provided to the Main module.
The Main module doesn't need to care what those low-level instructions are, it simply converts the Task to a Cmd and waits for the result.
When the result comes back it's in a low-level format (ex. Success/Fail). At this point the Main module can jump in and handle the redirect on a 401 error. Otherwise, it can pass the result to a feature module so it may handle the result.
I have the following errors that I am struggling to resolve based on the latest version of elm-lang/Navigation:
-- NAMING ERROR ------------------------------------------------------- Home.elm
Cannot find variable Navigation.makeParser.
231| Navigation.makeParser parse
^^^^^^^^^^^^^^^^^^^^^ Navigation does not expose makeParser.
-- NAMING ERROR ------------------------------------------------------- Home.elm
Cannot find type Navigation.Parser.
229| urlParser : Navigation.Parser Route
^^^^^^^^^^^^^^^^^ Navigation does not expose Parser.
Note:
It looks like Parser and makePaser were removed from Navigation in version 2.1.0.
Is there an updated example of how to do navigation leveraging the urlParser function?
I have the following:
import Navigation exposing (..)
main : Program Never
main =
Navigation.program urlParser
{ model = model
, update = update
, urlUpdate = urlUpdate
, view = view
}
...
-- NAVIGATION
parse : Navigation.Location -> Route
parse { pathname } =
let
one =
Debug.log "path" pathname
in
case pathname of
"index.html" ->
HomeRoute
_ ->
NotFound
urlParser : Navigation.Parser Route
urlParser =
Navigation.makeParser parse
The Parser concept was removed during the Elm 0.18 to simplify the API. Now you just need to supply a function that takes a Location and returns a Msg as the first parameter to program function.
That function could simply be a Msg constructor that takes a Location argument, as shown in the example from the examples directory (here is live example on ellie-app.com)
type Msg
= UrlChange Navigation.Location
Your update function would then handle the UrlChange Msg and act accordingly. You can still use Location parsing packages like evancz/url-parser.
Specifically, I am trying to initialize Elm with an already defined parameter. Something like:
initialModel =
{ me = window.user
, todos = window.todos
}
All I can find is how to get window dimensions using signals, but I'm on Elm 0.18 and it seems slightly outdated.
Edit: Just to be clear, the above code wouldn't work. Whatever was attached to the window object would have to be JS, so it'd have to go through a decoder.
You will need to use programWithFlags to pass initial values from javascript. The "flags" you pass from javascript should have equivalent record type if you want to use Elm's automatic type conversion:
Let's say your me is just a string, but your todos is a list of boolean flags and a label. Your Flags type could look like this:
type alias Todo =
{ done : Bool, label : String }
type alias Flags =
{ me : String, todos : List Todo }
Your init function would need to handle the flags value appropriately. Here is an example of just assigning the fields to Model fields of the same name:
type alias Model =
{ me : String, todos : List Todo }
main : Program Flags Model Msg
main =
Html.programWithFlags
{ init = init
, view = view
, update = update
, subscriptions = \_ -> Sub.none
}
init : Flags -> ( Model, Cmd Msg )
init flags =
{ me = flags.me, todos = flags.todos } ! []
Your javascript will need to be updated to pass in the flags. You do that by passing a json object as the first parameter to fullscreen or embed:
var app = Elm.Main.fullscreen({
"me": "John Doe",
"todos": [
{ done: true, label: "Do this thing" },
{ done: false, label: "And this thing" }
]
});
Here is a working example on ellie-app.com
If Elm's automatic json-to-mapping conversion isn't strong enough for your decoding, you could instead use the Json.Decode.Value type as your flag, then Json.Decode.decodeValue using your customer decoder. Here is an example on ellie-app.com of using a custom decoder.
Can anyone suggest, how can we add a dependency at build time in android gradle based on some condition like:
dependencies{
if(someCondition){
// add dependency
}
}
Thanks in advance!!
I found a solution for this:
Step1: Declare a boolean variable in gradle at root level.
like: def someDependencyEnabled = true //This could be dynamically set.
Step2: Using this boolean variable we can apply a check like:
if(someDependencyEnabled){
//Add some dependency
}
else
{
//Add some other dependency
}
Step3: Define Different source set for different situations:
android.sourceSets {
main {
java.srcDirs = ['src/main/java', someDependencyEnabled ? 'src/dependency_enabled_src' : 'src/dependency_disabled_src']
}
}
where:
'src/main/java' : is the common src file which contain common code.
'src/dependency_enabled_src': is the source folder that contain dependency specific code. which is further used by 'src/main/java'.
'src/dependency_disabled_src': is the source folder that contain alternate code when particular dependency is disabled.
In my case I wrote same name classes, methods & package name in both folders (dependency_enabled & dependency_disabled src) and wrote methods with desired implementation in dependency_enabled_src & empty methods for dependency_disabled_src.