I am trying to create a dynamic Vue3 template but template is not rendering.
import App from "./App.vue";
const app = createApp(App)
app.component("DynamicData", {
template: "#dynamic-data",
data: function () {
return {}
}
});
app.mount("#app");
And laravel blade file.
<div id="app"></div>
<script type="vue-template" id="dynamic-data">
<div>My Custom Template</div>
</script>
and this is how i am calling the template.
I am using <component :is=""> because these will be dynamic component.
<component :is="DynamicData"></component>
Related
This question already has answers here:
ref vs reactive in Vue 3?
(7 answers)
Closed last month.
When I import HelloWorld component into App.vue, I'm unable to see the content of contenutoHeader.
HelloWorld:
<template>
<h1>{{ contenutoHeader }}</h1>
</template>
<script>
const contenutoHeader = "Sto funzionando";
export default {
name: "HelloWorld",
};
</script>
App.vue
<template>
<div>
<HelloWorld />
</div>
</template>
<script setup>
import HelloWorld from "./components/HelloWorld.vue";
</script>
Any suggestion?
You need to add your state to the data, like so:
<template>
<h1>{{ contenutoHeader }}</h1>
</template>
<script>
export default {
name: "HelloWorld",
data () {
return {
contenutoHeader: "Sto funzionando"
}
}
};
</script>
Anything within the data is reactive and can be used in your template
GOAL: get API call from a headless CMS that returns a JSON with an array of content components with their settings and content
now, the CMS does not know if the components are available
neither does the APP, it tries to be dynamic
so, I am using vite / vue 3 and composition API
to get a component loading I am using this pattern
<script setup lang="ts">
const AdminPage = defineAsyncComponent(() =>
import('./components/AdminPageComponent.vue')
);
<script>
<template>
<AdminPage />
</template>
if I try to use directly assigned component it all works fine. The problem is when I am trying to use an array for it
<script setup lang="ts">
const contentPlaceholders = ref<any[]>([]);
const error = ref<any>(false)
const { data, status } = await axios.get('/get-content');
if(status === 200) {
data.forEach((placeholder: any) => {
contentPlaceholders.value.push({
component: defineAsyncComponent(() => import(`#/components/${kebabCase(placeholder.componentName)}/${placeholder.componentName}.vue`)
),
})
});
}
<script>
<template>
<Suspense>
<div>
<template v-for="placeholder in contentPlaceholders">
<component :is="placeholder.component"></component>
</template>
</div>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
</template>
I never get components rendered... even if I do just
<template>
<Suspense>
{{ contentPlaceholders }}
...
</Suspense>
</template>
If I do it with a fix array like this...
it works fine... unless the component does not exist
<script setup lang="ts">
import { kebabCase } from 'lodash'
let contentPlaceholders = shallowRef<any[]>([])
const comps: string[] = ['RichTitle', 'RichText', 'NonExistant']
comps.forEach((cmp: string) => {
try {
contentPlaceholders.value.push({
component: defineAsyncComponent(() => import(`#/components/${kebabCase(cmp)}/${cmp}.vue`)),
})
} catch (e) {}
})
</script>
<template>
<Suspense>
<div>
<template v-for="placeholder in contentPlaceholders">
<component :is="placeholder.component"></component>
</template>
</div>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
</template>
So how can I catch errors and make sure the app does not break when trying to import an non existent component?
As per the official documentation,
defineProps and defineEmits are compiler macros only
usable inside <script setup>. They do not need to be
imported and are compiled away when <script setup> is
processed.
The problem definition
I'm not able to use defineProps and defineEmits in <script setup> without importing it. Please refer to the error screenshot attached below.
The vue code which I'm executing
<!-- HelloWorld.vue -->
<template>
<h1>{{ props.message }}</h1>
</template>
<script setup>
// import { defineProps } from 'vue';
const props = defineProps({
message: {
type: String,
required: true,
}
});
</script>
The environment details for reference:
vue
^3.2.6 (3.2.19)
vue-cli
#vue/cli 5.0.0-beta.4
node:
v14.16.1
npm
6.14.12
We can resolve this issue with one of the below solutions.
Create Vue project with Vite. Follow this link for more information.
yarn create vite <project-name> --template vue
Add below rules in your eslint configuration file. Follow this link for more information.
// .eslintrc.js
module.exports = {
extends: ['plugin:vue/base'],
rules: {
'vue/script-setup-uses-vars': 'error',
}
}
I'm currently working on a new project where I have to integrate Vue 3 in a large Symfony/Drupal project.
The project already contains a lot of PHP code and actually I don't want to refactor too much to begin with.
Well I tried setting up a very small piece of Vue code to see how I could start working on the rest of the code. Actually I just want some PHP code to be transferred from index.html.twig to the sidebar.vue file. I also work with Webpack Encore by the way from Symfony. I read that I could use Vue components to achieve this but my components are not loaded inside my <div id="app"></div>. Or atleast not how I want them to load.
webpack.config.js (Webpack Encore)
var Encore = require('#symfony/webpack-encore');
if (!Encore.isRuntimeEnvironmentConfigured()) {
Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
}
Encore
.setOutputPath('webroot/public/build/')
.setPublicPath('/public/build')
.addEntry('main', './vue/src/main.js')
.splitEntryChunks()
.enableSingleRuntimeChunk()
.cleanupOutputBeforeBuild()
.enableBuildNotifications()
.enableSourceMaps(!Encore.isProduction())
.enableVersioning(Encore.isProduction())
.configureBabelPresetEnv((config) => {
config.useBuiltIns = 'usage';
config.corejs = 3;
})
.enableSassLoader()
.enablePostCssLoader()
// enables Vue
.enableVueLoader(() => {}, {
version: 3,
runtimeCompilerBuild: false,
});
;
module.exports = Encore.getWebpackConfig();
main.js
import { createApp } from 'vue';
import Sidebar from './components/sidebar';
const app = createApp({})
app.component('sidebar', Sidebar);
app.mount("#app");
sidebar.vue
<template>
<h1>Sidebar</h1>
</template>
<script>
export default {
name: 'Sidebar',
};
</script>
<style lang="scss" module>
</style>
index.html.twig
<div id="app"> <!-- The vue #app is loaded -->
<sidebar></sidebar> <!-- This is not loading -->
</div>
<!-- If it's loading I want to setup something like this -->
<div id="app"> <!-- The vue #app is loaded -->
<sidebar :item="{{ $item }}"></sidebar> <!-- This is not loading -->
</div>
{{ encore_entry_script_tags('main') }}
So how can I make <sidebar></sidebar> to load inside the HTML/Twig file? In the next step I would like to pass some PHP data on the <sidebar> component so I can read it inside the sidebar.vue file. Something like: <sidebar :item="{{ $item }}"></sidebar>
I'm not entirely sure if this is possible with my current setup but I would love to see it work like this or in a similar way.
It seems like I'll have to use the runtimeCompilerBuild. That solves the problem. When false Vue can only be used with single file components which performs better but is less suitable for my application at the moment.
.enableVueLoader(() => {}, {
version: 3,
runtimeCompilerBuild: true,
});
Instead of
runtimeCompilerBuild: false;
In your main.js do :
app.mount("sidebar");
instead of
app.mount("#app");
Have installed the angularjs and Twitter.Bootstrap packages succesfully
This is my index.html:
<!DOCTYPE html>
<html ng-app="TodoApp" xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="Scripts/jquery-1.9.1.js"></script>
<script src="Scripts/bootstrap.js"></script>
<script src="Scripts/angular.js"></script>
<script src="Scripts/angular-resource.js"></script>
<script src="Scripts/app.js"></script>
<link rel="stylesheet" type="text/css" href="Content/bootstrap.css" />
<title>Amazing Todo</title>
</head>
<body>
<div class="container">
<div ng-view></div>
</div>
</body>
</html>
This is my app.js:
var TodoApp = angular.module("TodoApp", []).
config(function ($routeProvider) {
$routeProvider.
when('/', { controller: ListCtrl, templateUrl: 'list.html' }).
otherwise({ redirectTo: '/' });
});
var ListCtrl = function ($scope, $location) {
$scope.test = "testing";
};
And, this is my list.html:
<h1>Test: {{test}}</h1>
This should work fine. However the index.html is not showing the content of list.html. I think the angularjs part is not working properly.
No idea about what am i doing wrong?
Once you have defined a module, you need to define your controllers for that module and not independently.
Thus, your controller should be rewritten as:
TodoApp.controller('ListCtrl', [ '$scope', '$location',
function ($scope, $location) {
$scope.test = "Testing";
}
]);
This should show the view in question.
I would say, that if you check errors in console (in Chrome or IE press F12) you should see:
...Failed to instantiate module TodoApp due to:
Error: [$injector:unpr] Unknown provider: $routeProvider...
The reason for this expectation is that we ask IoC to inject $routeProvider while not correctly listing dependent modules. This is the above code:
var TodoApp = angular
// here we say: we do not need any other module
.module("TodoApp", [])
// here we ask: inject $routeProvider from other module
.config(function ($routeProvider)
So to make it runing we have to include the module 'ngRoute'
var TodoApp = angular
// here we say: we need these modules to make our module working properly
.module("TodoApp", [
'ngRoute'
])
// now we can ask for the provider,
// using minification-safe syntax
.config(
[ '$routeProvider',
function ($routeProvider) {
$routeProvider.
...
}]);
And also do not forget to also reference this module scripts:
<script src="Scripts/angular.js"></script>
<script src="Scripts/angular-resource.js"></script>
<!-- here we have to load this module -->
<script src="Scripts/angular-route.js"></script>
What is your directory structure can you check if list.html is in the same directory as index.html, if not specify a relative path from the application root?
Since no one has posted a full correct answer to this question and it hasn't been closed yet, here is another answer.
This is your function:
var ListCtrl = function ($scope, $location) {
$scope.test = "testing";
};
This is a bare function, which isn't of much use. You need a controller so that Angular knows what to do with {{ test }}:
<div ng-controller="someController">
<h1>{{ test }}</h1>
</div>
If you insist on keeping the function as a separate variable, you could do so and still have a controller:
var ListCtrl = function ($scope, $location) {
$scope.test = "testing";
};
TodoApp.controller('someController', ListCtrl);
This also works.
Despite of this, your UI won't show, as there's an error in it:
var TodoApp = angular.module("TodoApp", [])
You're using $routeProvider and .when(),.otherwise(), for which you need ngRoute as a dependency:
var TodoApp = angular.module("TodoApp", ['ngRoute'])
Your app should work after that.