Issue with Highcharts not rendering in Durandal/Hot Towel Template - asp.net-mvc-4

We're using HighCharts.js in a Durandal/Hot Towel template in ASP.NET MVC 4. We are simply showing a proof of concept in using a charting API for a dashboard page. However, the graph is not rendering on the page during page load.
We have a custom .js file that holds the following code (copied and pasted from HighCharts.com):
$(document).ready(function () {
$('#reportgraph').highcharts({
chart: {
type: 'bar'
},
title: {
text: 'Fruit Consumption'
},
xAxis: {
categories: ['Apples', 'Bananas', 'Oranges']
},
yAxis: {
title: {
text: 'Fruit eaten'
}
},
series: [{
name: 'Jane',
data: [1, 0, 4]
}, {
name: 'John',
data: [5, 7, 3]
}]
});
});
And a div in an HTML view that is rendering correctly:
<div class="row-fluid">
<div class="span12">
<div class="widget">
<div class="widget-header">
<div class="title">Highcharts</div>
</div>
<div class="widget-body">
<div id="reportgraph" style="width:100%"></div>
</div>
</div>
</div>
</div>
The script bundler contains the following files:
.Include("~/Scripts/jquery-1.9.1.min.js")
.Include("~/Scripts/highcharts.js")
.Include("~/Scripts/custom.js")
.Include("~/Scripts/bootstrap.js")
.Include("~/Scripts/knockout-{version}.debug.js")
.Include("~/Scripts/sammy-{version}.js")
.Include("~/Scripts/toastr.js")
.Include("~/Scripts/Q.js")
.Include("~/Scripts/breeze.debug.js")
.Include("~/Scripts/moment.js"));
Yet the graph does not render. I've been able to successfully render the graph in a Bootstrap application, working with the scripts listed above.
Is there an extra step that must be done in order to work with functions inside document.ready statements on a single page application?
Thanks in advanced!

In a typical Durandal app there's no need to use document ready as at that point only the content of index.html (applicationHost) has been rendered. Everything else gets injected into the DOM by using Durandal's composition.
In order to work with these composed DOM fragments add a viewAttached callback in the vm that accompanies the html view. viewAttached gets the composed view passed in as parameter, which should be used to restrict the jQuery selector.
function viewAttached(view) {
$('#reportgraph', view).highcharts({
...
});
};
In most instances that should be sufficient to get jQuery plugins working. However in Durandal 1.2 viewAttached just ensures that the composed fragment is attached to its parent element not necessarily to the DOM, so you'd have to check if this is sufficient to get highcharts working. That issue will be addressed in upcoming Durandal 2.0 by introducing a documentAttached callback.

Related

Laravel Inertia Ziggy Link Routing Issue

I'm currently having a problem in my routing. Here's the scenario:
Inertia is working fine when there's no id query.
But after navigating to edit and I want to click any of the navigation links like clicking the Dashboard link, it throws a 404 code saying the page does not exist. Simply because instead of removing the /category/{id}, it adds dashboard at the end instead of removing the query.
Is there a way to fix this by not violating the inertia routing?
Here's the code:
Authenticated Layout
const navigation = [
{ name: 'Dashboard', href: 'dashboard', current: false },
{ name: 'Category', href: 'category', current: false },
]
<nav class="hidden lg:flex lg:space-x-8 lg:py-2" aria-label="Global">
<Link v-for="item in navigation" :key="item.name"
:href="item.href" :class="[item.current ? 'bg-gray-100
text-gray-900' : 'text-gray-900 hover:bg-gray-50
hover:text-gray-900', 'rounded-md py-2 px-3 inline-flex
items-center text-sm font-medium']" :aria-
current="item.current ? 'page' : undefined">{{ item.name
}}</Link>
</nav>
Have you tried using Ziggy? Ziggy Github repo
Then the routes you create using Laravel are made available using the same route function in Vue. It works well with inertia when creating laravel apps.
<Link
:href="route('frontend.categories.show', [categories, post.slug])"
>
If you check your console in the page inspector it should show you the ziggy routes pulled from the "web.php" in json format.
It automatically makes the standard Controller class functions available for your routes in javascript (so index, create, edit, show, destroy functions).
I would be happy to share my code I created from a tutorial utilising breeze like you are.
Solved it. Just needed to add "/" to the href navigation object.
const navigation = [
{ name: 'Dashboard', href: '/dashboard', current: false },
{ name: 'Category', href: '/category', current: false },
]

TinyMCE with Vue 3 configuration

I'm trying to use tinyMCE in VueJS. In numerous examples I'm seeing tinymce.init() being used within script tags:
<script>
tinymce.init({
selector: '#myTextarea',
setup: function (editor) {
editor.on('init', function (e) {
editor.setContent('<p>Hello world!</p>');
});
}
});
</script>
However, when I look at the TinyMCE Vue Integration documents, I see init being done directly in the HTML:
<div>
<editor
id="editor"
api-key="no-api-key"
:init="{
height: 500,
plugins: [
...
],
toolbar: '...'
}"
/>
</div>
The WYSIWYG initializes properly for me with init being done in the HTML section, but there are numerous instances where a function needs to go within init (see first code block) to load initial content, or deal with image uploads etc. This doesn't work with init being done within the <editor/> tag.
In VueJS with init being done within the <editor/> tag, how can I add the 'setup' function seen in the first codeblock?

Vue component not rendered on second visit

I have a Vue component that lists a bunch of clickable tags. When you click on a tag, it takes you to another page with a list of objects containing that tag.
The relevant parts of the component code are:
<template>
<div>
<h2>All Tags</h2>
<TagList v-bind:tags="tags"/>
</div>
</template>
...
<script>
import TagList from './TagList'
export default {
name: 'AllTags',
components: {
TagList
},
data () {
return {
tags: []
}
},
mounted () {
tags = // array loaded from a database
}
}
</script>
This all works fine when I initially view the page. However if I browse away from this list, e.g. by clicking on a single tag, and then browse back, I only see the <h2>All Tags</h2> header. Using the Vue debugger in the browser, I can see that the data are still there.
I'm using <router-view :key="$route.fullPath"> to control the overall app and suspect the problem lies with the keys somehow.
Can someone point me in the right direction here? How can I get the TagList component to render every time I visit that page of the app?
EDIT: Here's the code of the TagList component:
<template>
<div class="tags">
<Tag v-for="tag in tags" v-bind:tag="tag" v-bind:key="tag" />
</div>
</template>
<script>
import Tag from './Tag'
export default {
name: 'TagList',
props: ['tags'],
components: {
Tag
}
}
</script>
You can try removing v-bind all thought its not required to use, I've checked your code it seems to work fine after visiting a tag and going back, all tags are still rendered. You can take a look at this working sample .
https://codesandbox.io/s/vue-template-3tcs4?fontsize=14

Vue values not recognized in template

Trying out Vue for the first time and having some problem with some values not being recognized in the template even though they are set when checking with the Chrome Vue debug tool.
I'm doing this in a Wordpress context if that matters, with an inline template. I stripped down a lot of non-important code in my example below to just focus on the loader. I'm setting the loading value to true and here I'm not changing it anywhere. When loading the page I can see the spinner briefly then it disappears. However the value of loading is true when I check with debug tool. What am I doing wrong?
Javascript:
(function($) {
var employeesListingElement = document.getElementById('vue-employees-listing');
if ( employeesListingElement ) {
var EmployeesListing = new Vue({
el : employeesListingElement,
data() {
return {
employees: [],
filter: '',
errors: [],
loading: true
}
}
});
}
})(jQuery);
HTML
<div id="vue-employees-listing">
<div v-if="employees.loading" class="ajax-loader">
<p>Loading</p>
</div>
</div>
Your template should be
<div v-if="loading" class="ajax-loader">
employees is an array.

how to select first radio button without knowing the value using vue.js (and v-model)

In my use case the radio buttons is initially dynamically rendered by server. Then in client side I want to use v-model to handle the value change and related logic. The problem is that I want to pre-select the first button but in client side I don't know the value of it. What is the recommended way to do this in vue.js? If necessary the server can generate some "hint" for it.
I've been searching for a while but every working solution I saw assume the data is already there. One method I can think of is to make an api to return the buttons' value but this feels overkill.
JSFiddle
You can set the initial value of r in the mounted hook of the component to the value of the first radio button:
mounted() {
this.r = this.$el.querySelector('input[type="radio"]').value;
}
But it might be better to use a fixed template for the component that isn't rendered by the server in the first place. Instead of rendering HTML, you could render JavaScript containing the data for the items you want and then bind that data to the template.
Vue works best when the template is generated from the data instead of the other way around.
<script>
// Rendered by the server external to the Vue component,
// otherwise just render directly into the component's data
window.items = [
{ label: 'Apple', value: 'apple' },
{ label: 'Orange', value: 'orange' },
];
</script>
<label>
<input v-model="selected" v-for="item of items" type="radio" :value="item.value">
{{ item.label }}
</label>
new Vue({
el: "#app",
data: {
items: window.items,
selected: window.items[0].value,
},
});