0👍
Apparently Vue can only be mounted within one context element: .ui-model refers to several elements in the DOM, therefore just the first is rendered correctly (the menu). If I create another Vue app the code works as expected:
<div class="form-group" id="wallets-app">
@Html.LabelFor(m => m.WalletId, new { @class = "control-label col-sm-2" })
<div class="col-sm-10">
<select class="form-control" v-model="selectedWallet">
<option v-if="!walletsLoaded" disabled>Loading wallets...</option>
<option v-else v-for="wallet in wallets" v-bind:value="wallet.id">{{ wallet.description }}</option>
</select>
@Html.HiddenFor(m => m.WalletId, new { }, new { value = "selectedWallet" })
@Html.ValidationMessageFor(m => m.WalletId)
</div>
</div>
<script>
var app = new Vue({
el: '#wallets-app',
data: {
wallets: [],
walletsLoaded: false,
selectedWallet: ''
}
});
//SignalR code to sync hubs and ui
</script>
I wanted a single array of data to be shared between multiple elements, so that each element would’ve had its own html representation, its view. Instead I have to pass the array of wallets to each of the Vue apps I want to be reactive to updates.
Well, it seems unefficient to me, but I’m sure I’m missing something. Feel free to add any suggestions and/or corrections.
EDIT: the correct way to achieve the result I wanted was to simply put all the data into a store object, in order to share the same data across multiple components (such as menu items for each of the wallets).
<div class="form-group" id="select-wallet">
@Html.LabelFor(m => m.WalletId, new { @class = "control-label col-sm-2" })
<div class="col-sm-10">
<select class="form-control" v-model="selectedWallet">
<option v-if="!sharedData.walletsLoaded" disabled>Loading wallets...</option>
<option is="wallet-select-option" v-else v-for="wallet in sharedData.wallets" v-bind:wallet="wallet"></option>
</select>
@Html.HiddenFor(m => m.WalletId, new { }, new { value = "selectedWallet" })
@Html.ValidationMessageFor(m => m.WalletId)
</div>
</div>
<script>
var store = {
data: {
wallets: [],
walletsLoaded: false
}
};
Vue.component('wallet-select-option', {
props: ['wallet'],
template: '<option v-bind:value="wallet.id">{{ wallet.description }}</option>'
});
var selectWallet = new Vue({
el: '#select-wallet',
data: {
sharedData: store.data,
selectedWallet: ''
}
});
$(function () {
var walletsHubProxy = $.connection.walletsHub;
walletsHubProxy.client.updateWallet = function (...) {
...
};
walletsHubProxy.client.setWallets = function (currentWallets) {
store.data.wallets = currentWallets;
store.data.walletsLoaded = true;
};
$.connection.hub.start().done(function () {
walletsHubProxy.server.getWallets();
});
});
</script>
I forgot to mention that the @Html.HiddenFor with three parameters is an extension method I wrote to help me with v-bind attributes, which are unparsable by the razor syntax.