I'm doing a basic controller and trying to get data from the HTML with the tag value.
The problem is that the data is always empty
<div data-controller="selectable">
<div class="flex" data-selectable-iconurl="test" data-selectable-iconurl-value="test">
something here
</div>
</div>
Notice I did multiple combinations of the value tag ( from different posts) in order to verify if one is working.
Now when I try to access the values in the controller is always empty
// selectable_controller.js
import {Controller} from "#hotwired/stimulus"
export default class extends Controller {
static values = {iconurl: String }
connect() {
console.log(this.iconurlValue)
}
}
I double-checked the documentation and could not find why the value is not passed to the controller and is always empty
When Stimulus controller is on the same element as the value, you should be able to retrieve the value:
<div data-controller="selectable" data-selectable-iconurl-value="test">
If your value needs to be set on a child element, then I suggest to just access it the old way :
console.log(this.element.querySelector("div").dataset.selectableIconurlValue)
Though your value may just be treated like a common JS dataset component. You lose every Turbo goodness such as a mutation observer to the value : https://dev.to/borama/stimulus-2-0-value-change-callbacks-what-are-they-good-for-4kho
Not sure why the required location of the value is not precised in the Stimulus Handbook. Maybe I am wrong too and there is a way to have it acknowledged by Stimulus...
Related
grails v3.3.9, and bootstrap.
I have been wrestling with getting grails, fields and bootstrap to work happily when processing Java LocalDateTime. Nearly there but not quite ...
I have created a /fields/localdateTime/_widget.gsp like this
<div class="input-group date col-sm-8" >
<input id="${property}-label" name="${property}" type='datetime-local' class="form-control" value="${value}" placeholder="<empty>"/>
<div class="input-group-append" >
<button class="btn btn-icon-fixed-width btn-outline-secondary btn-block" disabled aria-disabled="true" type="button" >
<i class="fas fa-calendar"></i>
</button>
</div>
</div>
this uses bootstrap
when the edit action is triggered on show view, it correctly renders this field in the edit form, and fields plugin, reads the _widget.gsp and renders the field correctly.
The control (in chrome) seems to work ok, and i can select a date, and set the time in the input field
however when i submit the update button, the data posted back to the update action does not pick up my changed date value, but rather sends the original value that was in the domain object before hand.
worst however is that the controller gets the object passed to it and in the debugger the domain object arrives with correct id and what looks like a valid LocalDateTime in the debugger (albeit the original and not the edited value )
def update(BootstrapTest bootstrapTest) {
if (bootstrapTest == null) {
notFound()
return
}
if (!bootstrapTest.validate()){
println "object delivered to update action from edit form doesnt validate "
respond bootstrapTest.errors, view:'edit'
return
}
however whilst it looks ok - when you try and validate it fails
and whats rendered on the browser is "Property ldtProp is type-mismatched". What is wrong with the LocalDateTime validation?
I can create grails bootstrap data and save to db so its not the domain class nor validation when saving that way - its just when the record is delivered to the controller that it breaks
I've tried an equivalent field with LocalDate - and that seems to work and validates correctly, and i can save the object posted to the controller update action.
This is just so frustrating can any one elucidate on what this fails and what to do to correct it ?
this last bit has me stumped.
in order to wrestle with what fields plugin is actually doing, i've got a private version here private plugin copy with adjusted content
i've run run this as private clone of fields plugin because i couldnt watch what was happening under the covers, so this has a number of libraries, style sheets imported back in so i can do in situ debug. various /fields/xxx/*gsp defined to render the bootstrap form /display bits.
Blimey, another nest of worms...
First, the <input type="date" or <input type="datetime-local" as interpreted by chrome renders the browser value as 'mm/dd/yyyy' for date and for datetime-local as mm/dd/yyyy HH:mm:(ss:SSS - greyed out )
When you provide a value="string" it ignores your string - so you have to pass the actual value into input as value="${value}". If you convert that into a formatted field before, then it gets ignored, and default template is shown.
Next problem - when you submit the form the value sent to your params block is actually a ISO formatted string - not a LocalDateTime etc!
So when Grails tries to load the record from the db for you and inject it into your controller, its already tried to update the record once.
The problem is that this has fired a validation which has already failed. So when you get the domain object in your 'Update (Domain xxx) {...}' method the object already has its errors set.
So I tried to convert the strings sent in params to LocalDateTime, LocalDate, and then update my domain object in the controller - but they failed when using validate() as the preexisting errors where already there.
So I had to clear the errors first, then convert the params strings to the right Java date types and then update the domain object and then validate. This then is happy.
So the controller action now has to look like this
def update(BootstrapTest bootstrapTest) {
if (bootstrapTest == null) {
notFound()
return
}
LocalDateTime ldtProp
LocalDate dtProp
if (bootstrapTest.hasErrors()) {
bootstrapTest.clearErrors()
try {
ldtProp = LocalDateTime.parse(params.ldtProp?.toString()) //ISO_LOCAL_DATE_TIME
dtProp = LocalDate.parse(params.dtProp?.toString(), DateTimeFormatter.ISO_LOCAL_DATE) //ISO_LOCAL_DATE
bootstrapTest.ldtProp = ldtProp
bootstrapTest.dtProp = dtProp
bootstrapTest.validate()
} catch (ex) {
println "exception $ex.message"
respond bootstrapTest.errors, view:'edit'
return
}
}
try {
bootstrapTestService.save(bootstrapTest)
} catch (ValidationException e) {
respond bootstrapTest.errors, view:'edit'
return
} ...
So clear the errors first - then correct/convert the params map format to domain object format thats ok for the domain class property (or define set method in the domain that accepts a String and does the conversion internally)
Once you do that the re validation succeeds this time and your controller/db updates start to work.
Without using custom date pickers etc ( and for scaffolding that's overkill ) you have to live with the present data handling for
I have not tried this on another browser but Chrome is my 'normal' dev browser and behaves as indicated above.
--PS - additional trace. In the background when the Domain object is located and loaded, grails seems to have a convertor from String to DateTime, because i built a setDtProp (dt) setter - and this is called with converted value before the object is delivered to the controller - which is why I saw the dtProp change originally described, but no change to the ldtProp (where I have added a setter also in the domain object).
So however Grails is doing the injection process it doesn't do it for LocalDateTime as string from the browser (but it does put string into params for you ), but it will call a setter for LocalDate. Either way when the domain object is loaded its errors() has been set - so you need to handle this from the controller as shown. Trying to fix with setters in Domain class doesn't work for LocalDateTime as your setter is never called!
This can only to be handled in the controller once the object is injected as shown above, as I'd started to do in the first place.
I am using a ember components in a recursive manner and im going to make particular components as draggable in jquery-ui. so,i need to get its corresponding view id like "ember143" for the following HTML view,
<div id="ember143" class="ember-view"></div>
is there a way to get the id attribute?
NOTE: i know i cant set a unique class name to get its view element by
var Component = Ember.Component.extend({
classNameBindings: ["uniqueClassName"],
uniqueClassName: 'class143'
});
if it is possible, how to do that?
Ember Component has a elementId property which returns the id of the element in the DOM.
so you can get the component's id using `this.get('elementId').
More info here:
http://emberjs.com/api/classes/Ember.Component.html#property_elementId
I am using a strongly typed model for my view. I have a disabled text box whose value I update using javascript. The textbox is rendered using this
<%: Html.TextBoxFor(model => model.TotalAmount, new { disabled = "disabled"})%>
This renders a textbox with NAME and ID as 'TotalAmount'. TotalAmount is also a property on my model that binds to this view.
The javascript to update its value in the view is like this within its function:
document.getElementById('TotalAmount').value = {assigning new value here};
The function does get called and I can see the value in the disabled textbox when I change some value in another editable textbox. However, when I post this form to my action method as below :
[HttpPost]
public ActionResult Process (ProcessVM FormPostVM)
{
}
the disabled textbox property [TotalAmount] still has the old value but the editable textbox which I modified contains the new value I entered. Why does the disabled textbox not contain the javascript updated value?
I tried using
ModelState.Remove("TotalAmount");
in the action method above, but as I already figured it didn't work.
Any clues, tips?
Thanks for your time....
HTML input elements such as textboxes that have the disabled="disabled" attribute will never send their values to the server when the form is submitted. If you want to send the value to the server while still disabling the user from changing it you could make the textbox readonly:
<%= Html.TextBoxFor(model => model.TotalAmount, new { #readonly = "readonly" }) %>
Disabled inputs are never sent in a form submit, try using readonly attribute instead or hidden inputs
Disabled fields don't get posted. Try having a hidden form field that will send the value to the server, and set both TotalAmount and the hidden form field. On the server, use the value for the hidden field instead.
On a side note, since this looks like the order total, this is something I would recalcuate on the server rather than opening up the possibility of someone hacking the html and getting a discount on their product.
EDIT:
To the other's points, I'd forgotten about the readonly attribute. That will work too.
If you change it to use readonly rather than disabled, then this should give you the same functionality, but post the value.
Browsers don't post values back in disabled input controls, as you've discovered. Probably the easiest way to work around this is to hook onto form submission, and re-enable the input as the form is being submitted; the user won't have a chance to edit the value, and it should get posted with the rest of the request.
i think the last issue described it : please check it out :
Retrieving the value of a asp:TextBox
I have a view that is displaying a Drop down list using the HTML helper DropDownListFor
<%: Html.DropDownListFor(Function(model) model.Manufacturer, New SelectList(Model.ManufacturerList, Model.Manufacturer))%>
My controller is passing the View a ViewModel containing the Manufacturer and the ManufacturerList
Function Search(ByVal itemSrch As ItemSearchViewModel) As ActionResult
'some code mapping and model code'
Return View(itemSrch)
End Function
My ViewModel is nothing crazy just fills the ManufacturerList with a list of string values and then the Manufacturer property is just a string value containing the selected value from the drop down list.
Public Property Manufacturer As String
Public Property ManufacturerList() As List(Of String)
I'm having an issue with the view setting the selected value on the drop down list if we are reloading the Search View. I've checked the View Model (ItemSearchViewModel) when it comes into the Search function and the Manufacturer is populated with the proper selected value and successfully passes that value back to the Search View. At some point the data passed to the view doesn't seem to populate the selected value, was wondering if anyone had some ideas on why this is happening and what I can do to fix it.
Thanks
Didn't get much for answers on this so started digging into how I could fix this somewhat easily. Also in my research this seemed to be a common problem for many people with the DropDownListFor HTML Helper. I figured there had to be a way to get this working since I knew the selected value property from my ViewModel was actually getting passed to the View. So javascript and jQuery to the rescue, I ended up trying to set the selected value using the jQuery .ready function and was able to successfully get this to work. So here's my jQuery fix:
$(document).ready(function() {
$("#Manufacturer").val("<%: Model.Manufacturer %>");
});
For sake of making this easy to follow I used the full .ready syntax, or you can just use $(function () { 'code' });
If you want to solve this without using jQuery you can just use basic javascript syntax as well, it'll look something like this:
document.getElementByID("Manufacturer").Items.FindByValue("<%: Model.Manufacturer %>").Selected = true;
If you using the plain javascript call make sure to call this when the page is done loading data to the dropdownlist.
In either case all this code is doing is setting the selected value on the drop down list on the client side from the passed in Manufacturer value from the Model.
If you have any other ways to solve this problem please let me know, but this is working for me and hopefully it'll help someone else with their problem.
Thank,
I've done a similar quick-fix in JQuery today to fix this behaviour too :
$(document).ready(function() {
$(".wrapper<%: Model.Language %> option[value=<%: Model.Language %>]").attr("selected","true");
});
Though I could share it with others if needed.
I'd still like to see a real patch to this problem so many persons seems to have in a different way, maybe with an extension method of the already existing DropDownListFor Html.helper method.
I have a drop down in a MVC View, which is some thing like this:
Html.DropDownList(id, Range(0,10)
.Select(x => new SelectListItem {Text = x, Value = x}))
In the view itself, I need the selected value of this drop down. I know that I can access that in a JavaScript, but I am looking for a way to get it in the view itself from the drop down properties or something like that.
How can I access it? I tried to figure out some thing from intellisense but nothing relavant showed up, help is much appreciated.
Edit: I want the value after a few lines after the declaration of the drop down, I know that I can access it from JavaScript and by posting the form, Is there noway to access it on the view itself ?
Edit2: If its not possible to access it in view, please explain the reason, I am more interested in knowing it.
Thanks.
After reading at your question, it sounds like you want to have the drop down list supply a value for a lower section of the same page.
First and foremost, you will need to place the DropDownList within a form construct, as in:
<% using (Html.BeginForm("ProcessValue", "ThisPage")) { %>
<%= Html.DropDownList("DropID", Range(0, 10).Select(a=>new SelectListItem { Text = x, Value = x }) %>
<input type=submit value="Submit" />
<% } %>
You need to set up a few things ahead of time:
You have to have a submit button, or a similar construct, in order to retrieve the value of the DropID variable.
You need to set up an controller method that will handle the processing of the value, then redirect back to the original page with the selected value in the page's ViewData.
Finally, you need to set up the view so that the post-processing section will only display if you have a valid value in the DropID variable.
It's not as simple as just placing a DropDownList in a view and then using that value later on in the page. You have to get the controller involved to manage the data transport and you have to set up the single view to handle multiple states (ie. before the value is selected and after the selection takes place).
To get the selected value you could use either javascript or a controller action to which the form containing the select box is submitted.
The selected value will be in the FormCollection or QueryString collection with the name of the DropDown's ID in the controller action that receives the form submission from this view. You can either submit the values with a classic POST or GET or via AJAX, but you have to wire up a server-side action that processes that input.
There is a SelectList class as well wich allows you to define wich item will be selected.. and knowing that - you will know selected value..
Also.. if no value is selected explicitly, dropdowns tend to select the first item in the list.