Real time update between 2 components? - real-time

Is it possible to have a realtime update of input fields between two components?
In a component I have an input field which has a v-model="value". I wanna pass that input realtime to the other component and fill it into that input field.
Data of inputValue should be passed to the component 2 as value props. Or maybe I'm wrong with my result?
COMPONENT 1
<template>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" id="global-{{element}}" v-model="inputValue">
<label class="mdl-textfield__label" for="global-{{element}}">{{ label }}</label>
</div>
</template>
COMPONENT 2
<template>
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input name="items[{{prop1}}][{{element}}]" value="{{value}}" class="mdl-textfield__input"
type="text" id="{{element}}">
<label class="mdl-textfield__label" for="{{element}}">{{ label }}</label>
</div>
</template>
<script>
export default{
props: ['prop1', 'element', 'value', 'label']
}
</script>
I tried with ...
this.$dispatch('tag-update', this.inputValue);
... but I need an #keyup.xx. But that's not what I want. I want it to update as soon as I pressed and released a letter, number etc.

You can certainly achieve this with events, or you can move the inputValue up to the parent component or root and pass it to each component as a synced prop.
http://jsfiddle.net/gtmmeak9/118/
The second component doesn't have to be synced if you just want one way binding on it.

Related

Skip a loop in alpine.js with x-if

I use this loop
<form action="/" method="POST">
<template x-for="(deck, index) in $store.cart.decks">
<div x-show="$store.cart.total(index) > 0">
<div><span x-text="$store.cart.total(index)"></span> Karten</div>
<div x-text="deck.price"></div> €
<input :name="'deck[' + index + '][name]'" :value="$store.cart.decks[index].name">
</div>
</template>
</form>
Which works fine and displays all items in my cart and hides those that have a total of 0.
But this will only set the item with 0 on display:none, which will still transfer the data in the POST request.
I tried to use x-if instead of x-show but that is only allowed on a tempate tag.
I tried to add the x-if on the template tag:
<template x-show="$store.cart.total(index) > 0" ...
this results in an error, because index is not set at that point
I tried to add another <template> tag inside the existing template, but then the variables index and deck are not available inside the second any more
How do I prevent the zero cart items being computed in my POST request?
I think something like the following would work, note the div inside both template elements.
<template x-for="(deck, index) in $store.cart.decks">
<div>
<template x-if="$store.cart.total(index)">
<div>
<!-- rest of the content -->
</div>
</template>
</div>
</template>

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"
>

Dynamic AMP Selector

How can I change dynamically where it says 40,95€/mes to the option selected in the radio buttons using AMP?
<form id="myform" method="get" action-xhr="#" target="_top">
<amp-selector class="radio-selector" layout="container" name="my-selector">
<div class="background_gris_0" option="b">
<label>
<div class="clm1 left center_input">
<input name="answer1"
value="Value 1"
type="radio"
on="change:myform.submit">
</div>
<div class="clm8 left">Antes 10GB* / AHORA 20GB / Llamadas ilimitadas / 19,95€/mes</div>
</label>
</div>
<div class="background_gris_1" option="c">
<label>
<div class="clm1 left center_input"><input name="answer1"
value="Value 2"
type="radio"
on="change:myform.submit"></div>
<div class="clm8 left">Antes 20GB* / AHORA 50GB / Llamadas ilimitadas / 24,95€/mes</div>
</label>
</div>
</amp-selector>
</form>
<div class="center">
<h1> 40,95€/mes</h1>
</div>
JS Fiddle
This can be achieved by using the amp-bind component.
First of all, I would like to suggest you to remove all change events from radio buttons in amp-selector. Shift that 'myForm.submit' action to amp-select's 'select' event.
Create a state variable called 'currentPrice'. This will be null in the beginning. But when a radio input is selected, this will have a value and update the text in the h1 element.
So, in radio buttons add this (change the value of currentPrice accordingly):
on="tap:AMP.setState({currentPrice: '19,95€/mes'})"
Then, in the h1 element do this:
[text]="currentPrice"
So whenever the radio button is tapped, the text at the bottom will be updated with price.
You can see the jsfiddle here:
Js Fiddle
I have removed form submit event for simplicity.

Foundation 5 & Abide: a custom validator for a set of checkboxes?

I would like to create a validator for abide for a set of checkboxes.
Let's consider a set of 5 checkboxes. The user is asked to check 3 max, and at least 1.
So, here is my work-in-progress code:
<div data-abide-validator='checkboxes' data-abide-validator-values='1,3'>
<input type="checkbox"/>
<input type="checkbox"/>
<input type="checkbox"/>
<input type="checkbox"/>
<input type="checkbox"/>
</div>
<script>
$(document).foundation({
validators: {
checkboxes: function(el, required, parent) {
var countC = el.find(':checked').length;
alert(countC);
}
}
});
</script>
At this point, I just try to count the checked inputs. But it seems I can't even trigger the validator... I think I could manage to code my validation stuff if only I could figure out how to trigger it.
Indeed I didn't find many examples of the custom validator, and the official doc did not help me much.
Your HTML markup is not really "correct" for abide. You should be attaching the data-abide-validator attribute to the inputs, not the parent div. Additionally, you need some better markup so abide's default error display can work (and some better use of foundation's grid system to lay it out). I would point you toward the Abide Validation Page on Zurb's site for some examples of form markup.
I've taken the liberty of restructuring your markup to be something that is more becoming of a foundation layout:
<form action="/echo/html/" method="POST" data-abide>
<div class="row">
<div class="small-12 columns checkbox-group" data-abide-validator-limit="1,3">
<label>Check some boxes</label>
<small class="error">You have checked an invalid number of boxes.</small>
<ul class="small-block-grid-3">
<li>
<label>
<input type="checkbox" data-abide-validator="checkbox_limit" value="1" /> 1
</label>
</li>
<li>
<label>
<input type="checkbox" data-abide-validator="checkbox_limit" value="2" /> 2
</label>
</li>
<li>
<label>
<input type="checkbox" data-abide-validator="checkbox_limit" value="3" /> 3
</label>
</li>
<li>
<label>
<input type="checkbox" data-abide-validator="checkbox_limit" value="4" /> 4
</label>
</li>
<li>
<label>
<input type="checkbox" data-abide-validator="checkbox_limit" value="5" /> 5
</label>
</li>
</ul>
</div>
</div>
<div class="row">
<div class="small-12 columns">
<button type="submit">Submit</button>
</div>
</div>
</form>
As to your JS code. It's not correct either. You need to address the abide -> validators namespace of the options, not just validators. I've rewritten your JS code to not only do that, but give the desired effect you wanted:
$(document).foundation({
abide: {
validators: {
checkbox_limit: function(el, required, parent) {
var group = parent.closest( '.checkbox-group' );
var limit = group.attr('data-abide-validator-limit').split(',');
var countC = group.find(':checked').length;
if( countC >= limit[0] && countC <= limit[1] ) {
group.find('small.error').hide();
//return true so abide can clear any invalid flags on this element
return true;
} else {
group.find('small.error').css({display:'block'});
//return false and let abide do its thing to make sure the form doesn't submit
return false;
}
}
}
}
});
In order to check adjacent elements when doing custom validation, you need to have something to target. The el variable in the validation function will be the DOM element of the input/field that is being validated. The required variable will tell you if the field is flagged as being required or not (boolean). The parent variable will be set to the "parent" of the field. I say "parent" because although the label tag is technically the parent of the input element, abide is smart enough to realize that the label is part of the field's element structure and skip over it to the li element instead.
From there, you need a way to identify a common parent. So I added the checkbox-group class to whatever element I decided to make the "parent" of all the checkboxes in the group. This is not a Foundation or Abide "magic" class, but rather something of my own creation for use in the validation function.
From there, you can easily trace the few lines of the validation function to see the workflow: Find the group container object, parse the limits off the container's data-abide-validator-limits attribute, count the number of checked inputs in the container, check if the number checked is between the limits, display/hide the error message and return true/false so abide knows if the field validated or not.
I've got a working Fiddle of it if you care to check it out yourself ;) Hopefully this was informative for you, and I wish you the best of luck playing with the awesome that is Foundation!