How to bind variable window['array[element]'] in Ractive.js? - ractivejs

There is a need to have a two-way binding for a variable with such untypical name like "array[element]".
The syntax below works but when I change 0 to #index it gets broken. Adding back slashes before brackets [ ] does not work as well.
<input type="text" name="prices[{{#index}}]" value="{{someForm.inputs["prices[0]"].value}}" />
What is the proper syntax to get the variable binded?

You can use #context:
Ractive.DEBUG = false;
var ractive = Ractive({
target: output,
template: `
{{ #context.get('array[element]') }}
`,
data: { 'array[element]': "FOO" }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/ractive/1.0.0-build-99/ractive.min.js"></script>
<div id="output"></div>

Related

vue3 Cannot loop over an array of object passed as prop

In vue3 I am passing an array of options from parent component to child component in order to use it as options for a select.
At the moment, I am not able to use it to initialize my select.
Here is the child component SmartNumberInput
<template>
<div>
<div>Selected: {{ selected }} Initial:{{ initial }}</div>
{{ options }}
<div v-for="option in options" :key="option.value">
{{ option.text }}
</div>
<input type="number" v-model="input_value" />
<select v-model="selected">
<option
v-for="option in options"
:value="option.value"
:key="option.value"
>
{{ option.text }}
</option>
</select>
</div>
</template>
<script>
export default {
props: ["initial", "options"],
data() {
return {
selected: "",
input_value: "",
};
},
};
</script>
Here is the parent component
<template>
<div>
<h1>Hi! I am the root component</h1>
<div class="smart-number-input">
<smart-number-input
initial="B"
options="[{text:'Liters',value:'A'},{text:'Gallons',value:'B'},{text:'Pints',value:'C'}]"
/>
</div>
</div>
</template>
<script>
import SmartNumberInput from "./SmartNumberInput.vue";
export default {
data() {
return {
initial: "salut",
};
},
components: { SmartNumberInput },
};
</script>
<style>
.smart-number-input {
width: 100%;
background:#EEE;
}
</style>
In the result I get (see picture) there is no option visible in the select though when the small arrow is clicked it expands with a long empty list.
The {{options}} statement in the child displays what I pass as prop i.e. an array of objects but nothing is displayed in the div where I use a v-for loop.
When I declare the options as data in the child both loops (div and select) work fine.
Could somebody explain what is wrong in the way I pass or use the array of options ?
change options to :options (add colon symbol)
.
if you not put colon, it will treat the value as a String...

Assign value to input without v-model and without databinding

In my v-for i need to initialize some input field with some text WITHOUT binding it to the object. Currently i'm trying:
<div v-for="item in allItems">
<input type="text" class="header-title" value="item.name"></input>
</div>
but item.name is printed in the input instead of the item name. How to accomplish this?
v-model is just syntactic sugar for :value and an event, usually #input. See docs here.
You can pass a noop function () => {} to cancel the value update or do whatever you want with the new value, maybe assign it to another object.
Note: <input> elements are void, they do not require a closing tag.
new Vue({
el: '#app',
data() {
return {
allItems: [{ name: 'foo' },{ name: 'bar' }]
}
},
})
<script src="https://unpkg.com/vue#2.5.9/dist/vue.js"></script>
<div id="app">
<div v-for="item in allItems">
<input type="text" class="header-title" :value="item.name" #input="() => {}">
{{ item.name }}
</div>
</div>
You can have your input show value of item.value by only using the ref attribute.
Just add ref='' and map it's values to the inputs value, inside your mounted function.
new Vue({
el: '#app',
data () {
return {
allItems: [
{name: 'foo'},
{name: 'bar'}
]
}
},
mounted () {
let self = this;
this.$refs.inp.map( (m, k) => {
m.value = self.allItems[k].name
})
}
})
<script src="https://unpkg.com/vue#2.5.9/dist/vue.js"></script>
<div id="app">
<div v-for="item in allItems">
<input type="text" class="header-title" value="item.name" ref='inp'></input>
</div>
</div>

vue.js update value when another value changes (data-binding)

That's where I change a value:
<div>
<input type="text" id="global-tag1" v-model="liveTag1">
<label for="global-tag1">label</label>
</div>
And I would like to update it everywhere here:
Attention there are multiple of this pieces on my page. And I cannot do it with custom elements, I've done it and it worked but it takes to long to render the page.
<div>
<input name="someValue" value="{{$predefinedValue ?? ''}}" type="text" id="id1">
<label for="id1">label</label>
</div>
Now how do I achieve this with vue.js.
Because I cannot simply set
value="{{liveTag1}}"
Then I do not have a predefined value.
Solution
var vm = new Vue({
el: 'body',
data: {
liveTag1: ''
}
});
This will observe the liveTag1 and as soon as the data changes it will update the value of the given Selector.
vm.$watch('liveTag1', function(value) {
$('[id^="someid"]').val(value);
});
Which version of Vue are you using? On current version you cannot do:
value="{{liveTag1}}"
for input fields, you need to do:
v-model="liveTag1"
Then if you want to set it to a predefined value, in your Vue instance:
Vue({
data: {
liveTag1: "something"
}
})

Reuse Meteor template as inclusion with different helpers

I'd like to re-use a Meteor template as an inclusion (i.e. using {{> }}) in two different contexts. I know I can pass in different data with the inclusion by using {{> templateName data1=foo data2=bar}}, but I'm struggling to figure out how I can provide different helpers based on the context. Here's the template in question:
<template name="choiceQuestion">
<div class="choice-grid" data-picks="{{numberOfPicks}}" data-toggle="buttons">
{{! Provide for the user to make multiple selections from the multiple choice list }}
{{#if hasMultiplePicks}}
{{#unless canPickAll}}<span class="help-block text-center">Pick up to {{numberOfPicks}}</span>{{/unless}}
{{#each choices}}
<label class="btn btn-default"><input type="checkbox" class="choice" name="{{this}}" autocomplete="off" value="{{this}}" checked="{{isChecked}}"> {{this}}</label>
{{/each}}
{{/if}}{{! hasMultiplePicks}}
{{#if hasSinglePick}}
{{#each choices}}
<label class="btn btn-default"><input type="radio" class="choice" name="{{this}}" id="{{this}}" autocomplete="off" value="{{this}}" checked="{{isChecked}}"> {{this}}</label>
{{/each}}
{{/if}}{{! hasSinglePick}}
</div>
</template>
and here's how I've reused it:
{{> choiceQuestion choices=allInterests picks=4}}
The key component of the template is a checkbox. In one context, it will never be checked. In another, it may be checked based on the contents of a field in the user document. I've added checked={{isChecked}} to the template. I've read this boolean attribute will be omitted if a falsey value is returned from the helper which should work well for my purposes.
The template's JS intentionally does not have an isChecked helper. I had hoped I could provide one on the parent where the template is included in the other context in order to conditionally check the box by returning true if the checked conditions are met, but the template doesn't acknowledge this helper.
Here's the template's JS:
Template.choiceQuestion.helpers({
hasSinglePick: function() {
return this.picks === 1;
},
hasMultiplePicks: function() {
return this.picks > 1 || !this.picks;
},
numberOfPicks: function() {
return this.picks || this.choices.length;
},
canPickAll: function() {
return !this.picks;
},
});
and the parent's JS:
Template.dashboard.helpers({
postsCount: function() {
var count = (Meteor.user().profile.posts||{}).length;
if (count > 0) {
return count;
} else {
return 0;
}
},
isChecked: function() {
return (((Meteor.user() || {}).profile || {}).contentWellTags || []).indexOf(this) > -1 ? 'checked' : null;
}
});
Template.dashboard.events({
'click .js-your-profile-tab': function(){
facebookUtils.getPagesAssumeLinked();
}
});
I've tried a few other approaches as well. I tried passing the helper to the template along with the other context (i.e. {{> templateName data1=foo data2=bar isChecked=isChecked}}. This kinda works, but it calls the helper immediately. This breaks these since I need to use a value from the context to determine what to return from my helper. Since this value doesn't exist when the function returns, the function always returns undefined.
If I return a function from this helper rather than the value and then pass the helper into the template inclusion along with the data context, I get better results. In fact, my console logs show the desired output, but I still don't end up with the checked box I expect.
Here's what that looks like. Returning a function:
isChecked: function() {
var self = this;
return function() {
return (((Meteor.user() || {}).profile || {}).contentWellTags || []).indexOf(this) > -1 ? 'checked' : null;
};
}
and passing that to the template:
{{> choiceQuestion choices=allInterests picks=4 isChecked=isChecked}}
Is there an established pattern for overriding template helpers from the parent or for including helpers on the parent that are missing from the child template? How can I achieve this?

meteor test equality of a input value to a document field

Hello: I’m using the Tutorials todo.
I’ve been trying to compare an Input value
<input type="text" name="text" placeholder="Type Or Scan to add new Name" />
To the field named ‘text’ within a Document named ‘Tasks’.
Have tried EasySearch and {{#if $eq a b}} ... {{ /if }}.
May because I’m new to Meteor not setting up <templates> correctly.
Was hoping there is a short template or helper to compare or check the values to.
You can do this using a reactive variable.
Here's some example code:
JS:
Template.yourTemplateName.onCreated( function() {
this.input = new ReactiveVar(""); // Declare the reactive variable.
});
Template.yourTemplateName.helpers({
tasks() {
return Tasks.find(); // Find all tasks as an example.
},
isInputEqualToTaskText( taskId ) {
var task = Tasks.findOne({ _id: taskId });
if( task && task.text ) {
return task.text == Template.instance().input.get();
}
}
});
Template.yourTemplateName.events({
'change input': function( event, template ) {
template.input.set(event.target.value);
}
});
HTML:
<template name="yourTemplateName">
{{#each task in tasks}}
{{#if isInputEqualToTaskText task._id}}
<p>I was equal: {{task.text}}</p>
{{/if}}
{{/each}}
<input type="text">
</template>

Resources