salesforce lightning this.template.querySelector not working - salesforce-lightning

<template>
<div class="container-wrapper">
<div if:false={loggedIn} class="slds-m-around_medium">
<span>Login to Salesforce App</span>
<lightning-input name='username' label="Username"></lightning-input>
<lightning-input type="password" name='password' label="Password"></lightning-input>
<br/>
<lightning-button variant="brand" label="Login" title="Login" onclick={login}></lightning-button>
</div>
</div>
</template>
login() {
console.log('login attempt');
console.log(this.template);
var Username =this.template.querySelector('input[name="username"]').value;
var Password =this.template.querySelector('input[name="password"]').value;
console.log(Password);
console.log(Username );
}
values are not getting fetch in username, password variables.
this.template.querySelector('input[name="username"]').value is not working.
I have also tried onchange event approach on lightning-input elements , in that case event.target was undefined ? I am stuck not able to read user input.
app screenshot

There is no property 'name' on lightning-input like on standard HTML input. You should use 'data-id' instead.
HTML:
<lightning-input data-id='username' label="Username"></lightning-input>
JS:
let username = this.template.querySelector('lightning-input[data-id=username]');

The <template> element is not a common element. It holds its (inactive) DOM content inside a Document Fragment that you can access through the content property.
Therefore you should try:
var Username = this.template.content.querySelector('input[name="username"]').value;
var Password = this.template.content.querySelector('input[name="password"]').value;

In Salesforce when you are accessing a lightning input using the query selector first you have to search for lightning-input tag not the input tag.
Secondly when you add a name attribute to the lightning-input that attribute is transfered to the input tag which is created when the lightning component is rendered. But you can not access the input tag (my assumption is that it's in the Shadow DOM). Therefore to search for the lighting-input you must use a class name to identify the lightning component.
<lightning-input type="number" class="optionEditQuantityVal" value={Quantity} variant="label-hidden" step="1" max-length="1"></lightning-input>
let input = this.template.querySelectorAll('lightning-input.optionEditQuantityVal')

Related

meteor - how to code a bootstrap modal template to re-render html input values even if the user has typed in them

I'm using iron router to pass data to a bootstrap modal template. The modal contains a html form including many text inputs. The modal is re-used for 3 different features. I use a Session variable to keep track of which modal type is in use. Type 0 = blank form, type 1 = partial edit, type 2 = full edit. The form itself remains the same visually for all types. The only thing that changes is which input boxes contain a value.
For a type 1 edit only 2 boxes would contain values. For a type 2 edit all boxes would contain values. And the type 0 would be empty boxes.
// routes.js
Router.route('/mypage', function () {
var mtype = Session.get("mtype");
this.layout('myLayout');
this.render('my_popup', {to:'my_popup', data: function() {
switch (mtype) {
case 1:
return {box1:'box 1 text', box2:'box 2 text', box3:''};
case 2:
return {box1:'box 1 text', box2:'box 2 text', box3:'box 3 value'};
default:
return {box1:'', box2:'', box3:''};
}
}});
});
// main.html
<template name="myLayout">
{{> yield "my_popup"}}
</template>
<template name="my_popup">
<div class="modal fade" id="my_popup">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<div class="modal-title label label-primary">Title</div>
</div>
<div class="modal-body">
<form class="js-form-submit" id="my_form" name="my_form">
<div class="form-group">
<input class="form-control" type="text" name="box1" maxlength="64" placeholder="something" value="{{box1}}"/>
</div>
<div class="form-group">
<input class="form-control" type="text" name="box2" maxlength="64" placeholder="something" value="{{box2}}"/>
</div>
<div class="form-group">
<input class="form-control" type="text" name="box3" maxlength="64" placeholder="something" value="{{box3}}"/>
</div>
</form>
</div>
<div class="modal-footer">
<button class="js-form-ok btn btn-success btn-sm">submit</button>
<button class="btn btn-warning btn-sm" data-dismiss="modal">cancel</button>
</div>
</div>
</div>
</div>
</template>
Initially I tried passing an object to the modal template that only contained the properties that would be displayed. That didn't overwrite existing input values so I had to use the same object for each modal type and use empty strings for unused properties. I tried calling the reset() method on the form prior to showing the modal. In that case it caused the entire template to stop re-rendering.
Prior to showing the modal I set the session variable to the type of modal that will be displayed.
Session.set('mtype', 1);
That triggers iron router into sending the proper data to the template, unused properties are cleared and the template successfully re-renders.
Unfortunately if I type in one of the html inputs the template does not reset its value when it's re-rendered. This seems to be related to the same problem I encountered with the reset() method. If the input contains custom text (value is typed) then the modal doesn't display the new data sent to the template when the Session variable is changed. It preserves the user entered text.
What's the best way to re-use a bootstrap modal form in meteor? Should I use a helper instead of iron router to get the data object? Something like...
{{#with getData}}
Why is the user entered text being preserved?
I've also tried using the defaultValue attribute instead of value. The same issue occurs with both attributes.
To test the bug:
open the web console
Session.set('mtype',1);
$('#my_popup').modal('show');
type something in the 3rd text box
click off the modal to hide it
Session.set('mtype',0);
$('#my_popup').modal('show');
You'll see that the value you typed is still visible despite having sent empty strings to each box.
Another way:
Session.set('mtype',2);
$('#my_form')[0].reset();
Session.set('mtype',1);
$('#my_popup').modal('show');
You'll see that none of the boxes contain values despite having sent new strings of text to each box.
The only solution I've found is to use defaultValue in the template and then loop through the form fields before modal is shown and set value = defaultValue.
<input class="form-control" type="text" name="box1" maxlength="64" placeholder="something" defaultValue="{{box1}}"/>
Template.my_popup.rendered = function() {
$("#my_popup").on('show.bs.modal', function() {
var elems = $('#my_form')[0].elements;
for (var i=0; i<elems.length; i++) {
if (elems[i].hasAttribute('defaultValue')) {
elems[i].value = elems[i].getAttribute('defaultValue');
}
}
});
};

AMP autocomplete how get id from autocomplete results and display only text in input

view screen I am using https://amp.dev/documentation/components/amp-autocomplete/ and I am able show in results id and name concated in one string, but I need show only name and store id in hidden input.
code screen
<amp-autocomplete filter="substring" filter-value="name" min-characters="2" src="/ajax/get_active_clinics.php" class="name_autocomplete">
<input type="text" placeholder="Numele clinicii" name="clinic_name" id="clinic_name"
{literal}on="change:AMP.setState({clinic_name_validation: true, form_message_validation:true})"{/literal}>
<span class="hide"
[class]="formResponse.clinic_name && !clinic_name_validation ? 'show input_validation_error' : 'hide'">Clinica este obligatorie</span>
<template type="amp-mustache" id="amp-template-custom">
{literal}
<div class="city-item" data-value="ID - {{id}}, {{name}}">
<div class="autocomplete-results-item-holder">
<div class="autocomplete-results-item-img">
<amp-img src="{{link}}" alt="{{name}}" width="40" height="40"></amp-img>
</div>
<div class="autocomplete-results-item-text">{{name}}</div>
</div>
</div>
{/literal}
</template>
</amp-autocomplete>
You can use the select event on amp-autocomplete to get the event.value which will return the value of the data-value attribute of the selected item.
https://amp.dev/documentation/components/amp-autocomplete/#events
You can then call the split() string method on the result.
You'll need to modify the data-value in your mustache template like so:
<div class="city-item" data-value="{{id}},{{name}}">
Then add the following code to your autocomplete, this will assign the split values to 2 temporary state properties.
<amp-autocomplete
...
on="select: AMP.setState({
clinicName: event.value.split(',')[0],
clinicId: event.value.split(',')[1]
})"
>
Once these values are in state you can then access them using bound values. Note the [value] attribute, this will update the inputs value when state changes. It's worth mentioning that the change in value won't trigger the change event listener on your input here as it's only triggered on user interaction.
<input
type="text"
placeholder="Numele clinicii"
name="clinic_name"
id="clinic_name"
[value]="clinicName"
on="change:AMP.setState({
clinic_name_validation: true,
form_message_validation:true
})"
/>
Last thing you'll need to do is add the hidden input for Clinic ID, again this will need to be bound to the temporary state property clinicId.
<input
type="hidden"
name="clinic_id"
[value]="clinicId"
>

Why does reset() function does not work properly with jsviews

I am using jsviews for data binding:
My template
<script id = "ProfileTemplate" type="text/x-jsrender">
<input data-link="userVO.first_name" type="text">
<input type="reset" value="Reset" onclick="this.form.reset();">
</script>
My Form
<form name="profile-form" id="profile-form" action="profile.html">
<div id="flightEditDetail"></div>`enter code here`
</form>
<script>
var template = $.templates("#ProfileTemplate");
template.link("#flightEditDetail", profileJSON);
</script>
The template binds the value correctly. I changed the value in the text field and clicked on reset button. The text field becomes empty but I want the value that was rendered on page load.
Why does reset() function not work properly with jsviews data-link
reset() will revert the the intial/default value set in the value property: <input value="initialValue" />
For your case you could set the 'statically defined' value to the initial data value:
<input data-link="userVO.first_name" type="text" value="{{:userVO.first_name}}"/>
or better - attribute encode the initial value to avoid injection attacks:
<input data-link="userVO.first_name" type="text" value="{{attr:userVO.first_name}}"/>
The result is that the user will see the original value. However the reset action will only change the UI value, not the value in your underlying data that you are linking to. (See http://bugs.jquery.com/ticket/11043 for a related issue/concern in jQuery). So you would probably be better off not using reset() but instead cloning your initial data, and using $.observable(userVO).setProperty(originalUserVO) to revert.

Meteorjs - select DOM of a template from another template

I have the following
<div id="header">
{{> header}}
</div>
<div class="hidden content_box">
{{> content}}
</div>
"content_box" is hidden at the start.
template "header" has a single button.
<template name="header">
<button id="display_content">Click to display content</button>
</template>
template "content" is just a simple div
<template name="content">
It's me, content
</template>
When I click on the button in the header, I want to "show" the content_box.
How do I achieve this? - or better yet, what is the best way to achieve this type of effect where you need to access the DOM of a template from an event of another template?
Template.header.events "click button#display_content": (e) ->
Template.content.show() ?????
I don't know if it is the best way to do it, but in similar situations what I've done before is to use a session parameter to store the show/hide status of the div. In your click event, you then only need to change the value of the session flag. In the template of the div you want to show/hide, you just return the class name.
Example in JS:
Template.header.events({
"click button#display_content": function () {
Session.set('contentShow', true);
}
});
Template.content.className = function (input) {
return Session.equals('contentShow', true) ? '' : 'hidden';
};
Html
<template name="content">
<div class="{{className}} content_box">
It's me, content
</div>
</template>
You'd need to initialise the session flag to false in Meteor.startup() for example Session.set('contentShow', false);. As session is reactive, the div class name will be re-evaluated automatically when you change the session flag.

Submit the value of a <p> element when an html form is submitted

I have this code: <p class = "foo">Text</p>
And I also have a form: <form action = "XXX.php" method = post></form>
However, how can I get the value of the <p> when I submit it, as the <p> element can be changed.
So what I mean is to be able to post the value of the <p> when the user submits the form, and to be able to access it from that php file with: $_POST['foo'];
Thanks, I have tried to be as clear as possible.
You have to use Javascript for that
A jQuery function that will work
$("form").submit(function(){
var value = $("p").html();
// If foo already exists
if( $("[name=foo]").length > 0 )
{
$("[name=foo]").val(value);
}
else
{
var input = $("<input />", { name : "foo",
value : value ,
type : "hidden" });
$(this).append(input);
}
});
Use
<input type="hidden" value="something" name="something" id="something" />
and when you change inner html of <p> change the value of hidden input.
I think your best bet is to make it an input with readonly enabled, and style to to look like a <p>. It's better then trying to add it to the POST parameters with JavaScript.
Here's a quick example. I bet it could still be improved with a few extra CSS quirks, experiment a bit.
The easiest thing to do is set the value of a hidden form field when you change the contents of your <p>.
Alternatively, you can get its contents and post with JavaScript.
For text you need to use input field:
<input type="text"/>
Form fields should must have an id:
<input type="text" id="pewpew" class="foo"/>
I would go with:
<input type="text" id="pewpew" class="foo" value="default text goes here"/>
OR
Go with different workarounds, like setting form's hidden elements on the fly, etc.
You can create hidden field on the fly and set its value on form submit. Like this:
<form id="form" action="/somewhere" method="post">
<p>Some text</p>
<input type="submit" value="Submit"/>
</form>
<script type="text/javascript">
var form = document.getElementById('form');
form.onsubmit = function()
{
var p = this.getElementsByTagName('p')[0];
if (!document.getElementById('pval'))
{
var pinput = document.createElement('input');
pinput.setAttribute('type', 'hidden');
pinput.setAttribute('id', 'pval');
pinput.setAttribute('name', 'p');
this.appendChild(pinput);
}
document.getElementById('pval').value = p.innerHTML;
return true;
}
</script>
Works, i've tested.