Not long ago I hear about glimmer and decide to try it out.
Now I already try to do their tutorial and see the todo-mvc that glimmer already create but it seems that they use navigo to navigate through page.
I want to know if there's any proper way to setup route since previously I use ember.js and to setup route I just need to add another route at router.js.
Because of using navigo now I use code like this to navigate through routes
component.ts
import Component, { tracked } from '#glimmer/component';
import Navigo from 'navigo';
const router = new Navigo(null, true);
export default class MainPage extends Component {
#tracked routeName;
constructor(options){
super(options);
router
.on({
'/': () => { this.routeName = 'home'; },
'/posts': () => { this.routeName = 'postList'; }
})
.resolve();
}
};
template.hbs
<div>
<button>See All Posts</button>
{{#if (eq routeName 'postList')}}
<post-list />
{{/if}}
{{#if (eq routeName '404')}}
<h1>PAGE NOT FOUND</h1>
{{/if}}
</div>
Above code is working but it need me to have # after the domain. I think need to find another way or maybe more proper way than this one.
The current answer to your question is that Glimmer does not have such concept as routes. In future, you should be able to install parts of Ember - such as Ember routing to your Glimmer app.
Basically, it will work like this:
Glimmer application -> Installing all Ember packages = Ember application.
Or:
Glimmer application -> Installing only a few Ember packages = Glimmer + parts from Ember such as routing.
Related
I've got this big legacy web app based on Codeigniter and jQuery.
The plan is to phase out jQuery and start using Vuejs instead. We are replacing certain parts of the website step by step.
I have just installed Nuxtjs and got the file structure the way i like it inside the legacy project.
Now to the question. How can i access a Vue component from one of my legacy javascript files?
App.vue
<template>
<div id="app">
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App" />
</div>
</template>
<script lang="ts">
import Vue from "vue";
import HelloWorld from "./components/HelloWorld.vue";
export default Vue.extend({
name: "App",
components: {
HelloWorld
}
});
</script>
main.ts
import Vue from "vue";
import App from "./App.vue";
import store from "./store";
Vue.config.productionTip = false;
new Vue({
store,
render: h => h(App)
}).$mount("#app");
I want to display my App.vue inside an ordinary php/html view.
I am doing something similar right now, the project was originally written using Thymeleaf and jQuery and now we are switching to Vue.
You can communicate between vue components and non-vue components in a few ways, none of them are "pretty".
Communication
Classic JavaScript events
Pretty straightforward
// legacy code
document.dispatchEvent(new CustomEvent('legacy-vue.something-happened', { detail: payload }))
// vue component
created () {
document.addEventListener('legacy-vue.something-happened', this.onSomethingHappened)
},
destroyed () { // don't forget to remove the listener!
document.removeEventListener('legacy-vue.something-happened', this.onSomethingHappened)
}
Exposing EventHub
Similar to the previous one, but you are using vue events instead. This is what i would recommend, because it's the Vue way of handling events and your goal is to vuetify your app.
// initialization
const hub = new Vue()
Vue.prototype.$eventHub = hub
window.$vueEventHub = hub
// legacy code
$vueEventHub.$emit('something-happened', payload)
// vue component
created () {
this.$eventHub.$on('something-happened', this.onSomethingHappened)
},
destroyed () {
this.$eventHub.$off('something-happened', this.onSomethingHappened)
}
Exposing whole components
The most flexible way, but it's hard to see what's going on where. Event based approaches the lesser evil in my opinion (it's easy to track events).
// vue component
created () {
window.vueTableComponent = this
}
// legacy component
vueTableComponent.fetchNextPage()
vueTableComponent.registerOnPageFetchedCallback(callback);
Summary
No matter which approach you pick, i recommend doing something like this:
Let's say that you have TableComponent. TableComponent has few props like apiUrl, emits row-clicked event, etc. It would be best to design the component without thinking about your legacy code at all, and then create it's legacy wrapper because at one point it will be used both with vue-only screens and with mixed-screens (with both legacy components and vue components). An example:
LegacyTableComponentWrapper.vue
<template>
<table-component
:api-path="apiPath"
#row-clicked="onRowClicked"
ref="table-component"
/>
</template>
export default {
data: () => ({
apiPath: null
}),
methods: {
onRowClicked (row) {
this.$eventHub.$emit('table-row-clicked', row) // notify legacy code
},
onApiPathDefined (payload) {
this.apiPath = payload
}
},
mounted () {
// legacy code might require the TableComponent to act differently
// and if you don't want the TableComponent to know whenever it's legacy or not
// you can always override one or more of it's methods.
this.$refs['table-component'] = this.overriddenImplementationOfXYZ
},
created () {
this.$eventHub.$on('define-api-path', this.onApiPathDefined)
},
destroyed () {
this.$eventHub.$off('define-api-path', this.onApiPathDefined)
}
}
It's sure more work at first, but will save you a headache later, when you will be working on your first view which is fully in vue and all that legacy communication stuff is in the way.
My Ember.js has many components that the end-user can use to compose a page. How can I display a dynamic list of the components that exist in my Ember Application?
I imagine the registered components is somewhere in the Ember.Application object, but I'm having a hard time finding something I can use.
# in the route
import computed from 'ember-computed';
import getOwner from 'ember-owner/get';
...
{
components: computed(function () {
return getOwner(this).lookup('container-debug-adapter:main')
.catalogEntriesByType('component')
.filter(componentName => componentName.includes('composables'))
})
}
Is there any way to extend react-router of one application which is already hosted on fly? I want to inject additional routes on the click of a link which allows me to inject the script or allows to include my javascript.
Eventually I am looking for two different react applications which has one build and deployment cycle, but interrelated to each other.
Ex. there is the abc.com in which on click of a link(i.e. abc.com/nepage) the entire page is getting reloaded with same content [i.e. say header footer] which is maintained by different team all to gather and they have there one build and deployment cycle.
I want the application to be with SPA even if we have different build and deployment process.
This was achieved using Backbone with help of Backbone.Router.extend, where on click of link the default router for the new page was overridden with all new set of routers and which use to full the supporting files from the path mentioned for the specific router's
With PlainRoutes, child routes can be loaded on-demand (when the user enters the route) and resolved asynchronously. Having that in mind, you can use Webpack chunks to split the code corresponding to theses routes in diferente files. Going even further, you can have multiple entrypoints on Webpack, making users load only the part of the application that affects the current page.
Sample app:
index.js:
import React from 'react'
import ReactDOM from 'react-dom'
import { Router, browserHistory } from 'react-router'
const App = ({ children }) => {
<div>
<nav>Your navigation header</nav>
{ children }
<footer>Your app footer</footer>
</div>
}
const HomePage = () => <p>Welcome!</p>
const routes = {
path: '/',
component: App,
indexRoute: { component: HomePage },
getChildRoutes (partialNextState, cb) {
require.ensure([], (require) => {
cb(null, [
require('./routes/about'),
require('./routes/blog'),
require('./routes/contact'),
])
})
}
}
ReactDOM.render(
<Router history={ browserHistory } routes={ routes } />,
document.getElementById('container')
)
routes/about.js:
import React from 'react'
const About = () => <p>About page</p>
export default {
path: 'about',
component: About
}
Other routes could be similar to the about route as shown above.
I have a popup component in which i have a button and on click of that if im in my target route (mainRoute) i just want to pass the query parameters to my current route, but if i'm in another route i just want to transit with new query parameters. I know neither transitionTo or transitionToroute work. Is there any way to do that?
The transitionTo wouldn't work because you don't have access to routing from inside your component context. You can add the routing support at any place in your app using -routing service like so:
export default Ember.Component.extend({
routing: Ember.inject.service('-routing'),
someFuncUsingRouting(){
let routing = this.get('routing');
routing.transitionTo('some-route');
}
});
This is my code for logout function that close the session and redirect you to /login route.
import Ember from 'ember';
export default Ember.Component.extend({
authManager: Ember.inject.service('session'),
routing: Ember.inject.service('route'),
tagName: '',
actions: {
invalidateSession() {
console.log("logout invalidateSession");
this.get('authManager').invalidate();
let routing = this.get('routing');
routing.transitionTo('login');
}
}
});
This is working code for:
ember-cli: 2.8.0
node: 7.1.0
I am creating an Ember application using the Ember CLI. I have a view which invokes a component that I created. I am trying to access the global App variable to create my component and insert it into my layout.
The error: Uncaught ReferenceError: App is not defined
How do I fix this?
app.js
import Ember from 'ember';
import Resolver from 'ember/resolver';
import loadInitializers from 'ember/load-initializers';
Ember.MODEL_FACTORY_INJECTIONS = true;
var App = Ember.Application.extend({
modulePrefix: 'client-web', // TODO: loaded via config
Resolver: Resolver
});
loadInitializers(App, 'client-web');
export default App;
item-table.js (This is a view)
import Ember from 'ember';
export default Ember.View.extend({
templateName: 'item-table',
didInsertElement: function() {
// All my other code here
App.FreestyleChartComponent.create().appendTo($('#wp-chart td')); // This throws an error.
}
});
app/components/freestyle-chart.js
import Ember from 'ember';
export default Ember.Component.extend({
templateName: 'components/freestyle-chart',
didInsertElement: function() {
console.log('Inserted the component.');
}
});
I can think of two ways. The first is to put the App in the global scope manually.
var App = window.App = Ember.Application.extend();
The second is to import the App into your view:
import App from './path/to/app/file';
The latter is only possible if Ember CLI supports circular references. The official ES6 spec supports them but many transpilers don't (mine doesn't).
However, I don't think this is your root concern. For the most part, you shouldn't be accessing global variables in Ember CLI. Instead of placing the FreestyleChartComponent in the App namespace, why not just put it in a module and import it like any other module? Global variables are unavoidable (I experienced that today), but you should try to minimize them.
I do agree that you should not be accessing your app via the global namespace, however ember-cli actually does actually make you app a global with the name of your app being the name of the variable.
If you open /app/index.html in your ember-cli project you should see a script tag towards the bottom that looks like...
<script>
window.YourAppName = require('your-app-name/app')['default'].create(YourAppNameENV.APP);
</script>
in the above example YourAppName would be your app available as a global
Import the component that you want:
import FreestyleChartComponent from 'app_name/app/components/freestyle-chart';
There is no straight forward way to do this since Ember CLI wants you to use the public API and its given components rather than accessing the App instance directly.
Most solutions consist of making the App instance global, whereby this one does not. I did not test this, but I think this should work:
appname/utils/application.js
export default {
instance: null
};
appname/instance-initializers/application.js
import application from 'appname/utils/application';
export default {
name: 'app-initializer',
initialize: function (application) {
application.instance = application;
}
};
Now
import application from 'appname/utils/application';
and use application.instance in any file where you need the application instance.
Justed tested with Ember 3.7.
import App from 'app-name/app';
app-name has to be replace with the name of your app (I guess the one in package.json).