Aurelia dynamically bound variable with template string - aurelia

I am trying to set the dynamic id of a component within a component.
So the child component has a bindable uniqueId property.
The parent component has its own uniqueId which I am trying to keep into the child component's uniqueId, as such sort of following BEM convention:
<text-input-editor repeat.for="boxSide of boxSides"
uniqueId.bind="box-editor-${uniqueId}__${boxSide}-input"></text-input-editor>
But this gives me the following error: unconsumed token { (abridged).
I tried with using the <let></let> element as in https://aurelia.io/docs/templating/custom-elements#declarative-computed-values but that didn't work either.
I am not sure how to do this in the view, as I would rather not handle this at the controller's level (this is just one of many components in that view).

Assuming uniqueId has a value in your viewmodel, as the expression already has a ".bind" format, this would be:
<text-input-editor repeat.for="boxSide of boxSides"
uniqueId.bind="'box-editor-' + uniqueId + '__' + boxSide + '-input'"></text-input-editor>
Otherwise, it could be:
<text-input-editor repeat.for="boxSide of boxSides"
uniqueId="box-editor-${uniqueId}__${boxSide}-input"></text-input-editor>
A working version can be reviewed at:
CodeSandbox

So I didn't try specifically Cristián Ormazábal's answer but I fixed my problem by changing uniqueId to unique-id:
<text-input-editor repeat.for="boxSide of boxSides"
unique-id="box-editor-${uniqueId}__${boxSide}-input""
></text-input-editor>

Related

Vue.js get element by id/ref

I have a custom component called 'menu-entry':
<menu-entry v-for="field in fields" :id:"field.id" :ref="field.id" v-bind:key="field.id" v-bind:class="[classArray]" v-bind:field="field" v-on:clicked="menuEntryClicked">
</menu-entry>
I need to get one of them (for example field.id = 2) and remove an item from the classArray.
this.$refs[2] is working for HTML elements, but not for custom elements.
this.$el.querySelector isnt working either.
is there another way to remove an item from the classArray of a specific element?
Your question it is not clear but you are trying to set id and ref to field.id so following this logic it is not necessary to do though.
You can just send the id to the method you are executing like below:
<menu-entry
v-for="field in fields"
v-bind:key="field.id"
v-bind:class="[classArray]"
v-bind:field="field"
v-on:clicked="menuEntryClicked(field.id)" // <= send the id here
>
</menu-entry>
I am not sure if i helped but regarding your question, now you can figoure out which id of element is clicked and remove it from classArray or whatever you want
2 is not a valid id selector when you use document.querySelector('#2'); maybe you can use document.getElementById('2') instead - it can work.

possible to dynamically add objects to an array and have Vuejs detect it

edit 2
I think the issue is how I'm referring to an array from a parent component. A fiddle is provided in the comments.
I have an app where we want to be able to add items to a menu_header. I have tried pushing to the bottom of the array but Vuejs doesn't seem to be detecting it.
I have read this section https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats and am trying to make this work but I'm not sure if this is possible.
Something like:
var obj = { name: "my name" }
menu_header.items.push(obj);
Do I need to use this.$set syntax? I really need to add into the middle of an array via splice.
edit 1
So this is a component that is recursive (ie a menu_header can have many menu_headers). I have tried adding a simple button in a menu_item to add to the parent component like this:
methods:{
addItem: function(){
var items = this.$parent.$data.menuHeader.menu_items;
var obj = { header: "my header", detail: "this detail"}
console.log("11 items length: " + items.length);
items.splice(1,0,obj);
console.log("22 items length: " + items.length);
},
The count of the number of items is incremented but the view doesn't rerender. This component is nested 3 levels deep (a Menu component has many MenuHeader components which can have many MenuItem components and also have many MenuHeader components). I'm pretty sure it's a reactivity / array issue - but not sure about exact problem.
Really the issue here was that you should use a key with a list in order for Vue to property render it in all cases and when you are iterating over a component you must use a key. The code in the fiddle is properly adding the elements to the array and Vue is detecting the changes, it just doesn't properly render the list because of it's update strategy. Using a key fixes that.
To that end I modified these lines in the template.
<div v-for="menu_header in menu.menu_headers" :key="menu_header.name">
and
<div v-for="(menu_item, idx) in menuHeader.menu_items" :key="menu_item.header">
The best key for these is some unique property of the object in the list. The above uses name and header, but I expect with real code you could come up with a better key.
It's best to get in the habit of always adding a key whenever you render a list in Vue.

VueJS Component Input Sync

I want to create components which have input which two-way bind to the local scope of the component.
Without a component, I would create a new Vue instance and then set my data to what I need. Then using v-model, bind an input to that data and it can be manipulated from the input.
However, converting the same code to a component, I cannot for the life of me get any input in a component to bind to its data. I have tried props, :data.sync, data attributes but no matter what I have tried, the input within a component does nothing.
I have created a JSFiddle to illustrate this:
https://fiddle.jshell.net/f0pdmLhy/2/
What I would like to happen is the input in the component to two way bind to the err variable, just like the non component version underneath.
How would I accomplish this?
I basically want to create components that I can instansiate with ajax data and then populate the inputs. The inputs could then update the data and I can use a save method to send the data to the server. Can this even be done using components?
So there are a couple of things:
The external resource you were using was somehow faulty. I've used
jsfiddle default Vue instance and it works fine.
When you declare a component, you should not define the data as an object, but as a function returning an object. Read here: https://vuejs.org/guide/components.html#Component-Option-Caveats
A working example here: https://fiddle.jshell.net/by4csn1b/1/
Yes, with components, the reactivity can be accomplished just like with an instance.
One catch with components, is that data must be a function that returns an object.
Also, to maintain the two way binding, use v-model in your input.
Vue.component('ii', {
template: '<span>{{err}}</span><input type="text" v-model="err"><hr>',
data: function () {
return {
err: 123
}
}
})
Fiddle: https://fiddle.jshell.net/f0pdmLhy/25/

Aurelia: Trigger update on one custom element when a value in another custom element changes?

I've just recently asked a question ( Refreshing i18n translated string interpolated values in Aurelia ) regarding how to refresh i18n string interpolated values when a select input field (with language ids) changes. I received a great answer, however now I realized that there was another requirement.
It's not only string interpolated values that needs to be refreshed.
In my page-specific templates I have some select fields (custom elements), which gets their option values from injecting a "service" class. That service is responsible for doing the http fetch request, and returning a promise to the select field (custom element).
Now here's the problem. When the global (language) select field from my site-wide nav-bar custom element changes, and i18n refreshing happens using the notification approach proposed in the link above. How would I then also re-fetch my different select input custom elements inside the template, but with the new language id from the language select in the nav-bar?
The only solution I know so far is to do window.location (router.navigate(sameroute) didn't trigger a refresh) and refresh the current page whenever the language select changes, however that's obviously not a great way to handle this.
I'll try to see if I can put together a plunkr, since all this may sound a little confusing.
#chrismbeckett from in https://gitter.im/Aurelia/Discuss gave me this hint:
"For those types of inter-component syncs, use the EventAggregator.
Pub a 'lang-changed' event and let any component do what it needs to
update itself"
So in nav-bar.js i did this:
let payload = { 'lngId': this.appLngId};
this.eventAggregator.publish('lang_changed', payload);
and in the custom element which were to be refreshed I put this inside the attached() function:
this.eventAggregator.subscribe('lang_changed', payload => {
alert(payload.lngId)
self.myTodosService.getMyTodos(payload.lngId);
.then(function(data){
self.myTodos = data;
})
});

Confusion using dijit.byId and dojo.byId

I am trying to understand the difference between
dijit.byId and dojo.byId
For this i have taken a Button and a div .(To set the
data inside the div on click of the Button)
Show Me!
<div id="findMe">
Hiya!
</div>
This is working (dojo.byId)
function callMe()
{
var node = dojo.byId('findMe');
node.innerHTML = "Hello World";
}
But this isn't working (dijit.byId)
function callMe()
{
var node = dijit.byId('findMe');
node.innerHTML = "Hello World";
}
My understanding is , when refering to the div we need to use dojo.byId
and when we are refering to Individual components use dijit.byId
Please correct me if i am wrong .
As previously stated, dojo.byId retrieves the DOM node with that id if existent.
dijit.byId retrieves the instance of a dijit._Widget (and its subclasses), that is dojo's abstraction of UI objects, rather than the widget's DOM node. But it is important to note that dijit.byId searches through the widgets by the atrribute "widgetId", not "id". These are equal if you declare your widgets by passing a container node that already has an "id", but still dojo creates an attribute "widgetId" for every widget if not specified explicitly.
This means that widgetId and id are usually the same, but it is possible that they are different. Plus, widgetId is always set for a given widget even in cases where the id attribute of the container node is absent.
This implies that you should use dojo.byId whenever you intend to work on the DOM tree itself and dijit.byId only in case where you'd like to obtain the instance of a certain widget instance. If no widgets are present, there is no reason to use dijit.byId at all.
You are right:
dojo.byId finds elements in the DOM tree of your website with a certain ID - it searches and returns HTML elements.
dijit.byId finds dijits you created with a certain id - it searches and returns dijits (javascript objects), although these objects usually refer to a certain DOM node.