Achieving simple tasks with vue (Laravel) - javascript

Ive recently started learning vue.js (Coming from angular 2+), Ive watched a few tutorials and it all seemed to go swimmingly.
As always after ive finished doing the tutorials, I create a little app for myself just to ensure I know what im doing. But I seem to be really stuggling with Vue.
So far the app is very simple. A user posts a story, The story has comments.... simple as that
I got to the point where I wanted the user to be able to edit there comment, But It seems I cannot work out how to do this. I would like it so that when the user clicks the edit button the comment changes to a textarea or an input of some kind.
At this point I have not used to vue in the project at all. All the pages are rendered with blade.
Im trying to get my head round how you are meant to use it? So I have the following questions
Are you meant to use multiple vue components, Loop in blade and create a on each iteration?
<div id="app">
#foreach($comments as $comment)
<comment {Stuff passed in}></comment>
#endforeach
</div>
Are you meant to have that one vue "app" that gets the data from the api and loop them within the vue component?
const comments = new Vue({
el: '#comments#'
})
As all the site is a multipage application (Dont want to go down the SPA route) and lets say I now have a products page, The product has a list of attributes (Pretty much the same as comments). Do I create another vue app?
const comments = new Vue({
el: '#comments',
});
const productThings = new Vue({
el: '#productThings'
})
If I want to sections on a page controlled by vue (Lets say the comment section and another interactive section) Would this have to be 2 vue "apps" like in the above code example, One that is "comments" and one that is "somethingelse" or would the whole page have to be one big vue component.
// Comment loop, How ever this gets handled with vue
// Some other content
// Another place I need it to be interactive````
This seems very complicated just to acheive simple tasks, Also seems as if it would get out of control very quickly (I could only imagine coming back to this after 6 months and trying to work out what was going on).
You can see how confused I am with it all, The more I read the more confused I seem to get.

Vue is used to create fully fledged SPA web applications but can only be used as a drop-in without build process for simpler use cases. Usually you would integrated Vue Router to create a multi-page experience, but you can also just define single components and mount them on an element. In your case, with the mixing of PHP and Vue, I would suggest going for the way without build process and drop-in components.
Vue is a JavaScript framework with static templates. So, you should not generate dynamic templates and then pass them to Vue, but rather define static templates and then pass only the data to Vue. You can e.g. fetch the data via Ajax in a JSON format and then process this data to e.g. render a list of comments.
If you go for using Vue as a drop-in without routing, you need to mount two separate Vue instances on their respective pages. You can of course reuse parts of these components. Keep in mind, that you cannot share data between these instances (one of the benefits of using a SPA). You could however share the data via LocalStorage/SessionStorage/IndexedDB.
One common way to access the data is via a REST API (via Ajax/fetch). You would provide the data in a proper format (usually JSON) behind a HTTP REST interface. Then, Vue fetches the data (see also axios for easy data fetching) and then uses it to build up the components. Another approach (less nice) is to just render the data with your server-side programming language and put it into a JavaScript variable, so, that you have access to the data on runtime.
Here is a basic example. Keep in mind that binding a value from a property is an anti-pattern and therefore I did not bind the comment text in a two-way manner. I have also hard-coded the comment data and do not fetch it from remote.
Vue.config.devtools = false;
Vue.config.productionTip = false;
Vue.component('comment', {
data () {
return {
commentAsInput: false
};
},
props: {
commentObject: {
type: Object,
required: true
}
},
template: `<div>
<a href="#" #click="commentAsInput = !commentAsInput" v-if="!commentAsInput">
{{ commentObject.text }}
</a>
<textarea :value="commentObject.text" v-if="commentAsInput" />
</div>`
});
Vue.component('comments', {
data () {
return {
comments: [{ id: 124, text: 'fkgnsdklgnl' }, { id: 2135325, text: 'nlekng345gn' }]
}
},
template: `<div>
<h1>Comments</h1>
<div v-for="comment in comments" :key="comment.id">
<comment :comment-object="comment" />
</div>
</div>`
});
new Vue({
el: '#app',
template: `<comments />`
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>

No, typically you'd use a Vue component to iterate and render out each comment (possibly as sub-components).
You can fetch the data from an API, or render it into your blade template for Vue to use (saves on an API call and having to set up an API endpoint if you don't already have one).
If you're using the Vue scaffolding that Laravel provides, then a Vue instance is initialised on any page where the app.js bundle is loaded and attached to an element with the ID app, if there is one. Inside this element Vue will parse any template directives and render any components that have been registered. So you could register additional components (e.g. ProductThings) to put into different blade templates.
As I mentioned above, Laravel creates a single Vue instance. There's nothing that stops you rendering out static content via blade into the app container, which Vue will leave as-is, between components which contain independant functionality.

Related

splitting code using laravel mix for a project that only uses vue on several pages

I'm currently doing front-end optimization for a project and I'm stuck with code splitting..
basically what I'm trying to achieve is splitting code and vendors and load specific ones only when needed.
Currently, I use the default mix setup and all the dependencies are imported into app.js. So I need to include app.js on every page, which is very inefficient because in my project, most of the pages don’t use vue and I used some REAL big vue plugins on some of the pages that utilises vue...
For instance, say I have two pages: /home and /orders. Instead of loading app.js on every page, I'd like have:
/home (most pages look like this)
vendor.js: jquery + bootstrap + jquery plugins
home.js: initializes some jquery plugins (e.g. carousels) on the page
/orders
vendor.js
vue.js: I'd like to extract vue because I have multiple entry points
order-index.js: registers page specific vue component and creates vue instance
// order-index.js
Vue.component('order-index', require('./components/OrderIndex.vue'));
const app = new Vue({
el: '#app'
});
How can I achieve that using laravel-mix? Or do you guys have any better suggestions?
Thanks!

How can I add Vue or React to an existing Wordpress site?

I'm wondering what's the best way about adding a front end, componentized framework to a Wordpress site without using the Rest API.
I'm taking over two sites built with the Woocommerce Storefront theme, and I'd like to add a reliable front end library. Would it be best to just build my own as I need it? I'd like to avoid jQuery as I find it gets messy pretty quickly.
Would a good course of action be to build a plugin which generates a Post type with the framework added in, or is there a way I can add my framework to the whole site and implement it incrementally.
If you start a new project from scratch, I would recommend using Sage: https://roots.io/sage/.
One big deal when it comes to use React / Vue.js for any kind of projects is you need to setup the build (using Webpack for example), to compile them and get the best of out these frameworks. Sage takes care of these tasks for you and have webpack and browserify integrated so you have hot loading for dev and proper build for production. That's really an advantage.
With your case, because your sites have been built using Storefront, so integrate fully with Sage seems to be not an option, however, you can still borrow some ideas from Sage.
Sage set it scripts up in the way that your script can be separated into routes, though these routes are not exactly the same as ones of a single page app. Basically, they have an util function called Router, which will execute JS functions based on the classes inserted into the body element. I find it works extremely well with Vue.js and React. For instances: in your homepage, you want to place couple of Vue components inside a <div id="homepage"> element, you can define it as follows:
export default {
init() {
new Vue({
el: '#homepage',
name: 'HomePageApp',
components: {
...
},
});
},
finalize() {
// JavaScript to be fired on the home page, after the init JS
},
};
Then import and add it to your Router:
const routes = new Router({
...
// Home page
homepage,
});
I recommend having a look at how Sage does that in your Github repo, it's pretty straight forward and guarantee a well-organised, well-structured front-end: https://github.com/roots/sage/blob/master/resources/assets/scripts/main.js

Override ember component template with template from addon (in-repo)

I want to create an in-repo addon to make certain modifications (styles, templates, etc.) to an existing ember app in an encapsulated way, but I'm having troubles overriding the templates.
Right now, I'm trying to override an existing component template with the template from a component with the same name in the in-repo addon. My code looks something like this:
// my-app/app/templates/components/foo.hbs
<h1>Some headline<h1>
// my-app/app/lib/my-addon/app/templates/components/foo.hbs
<h1>A different headline<h1> // -> this never shows up
I've tried a lot of switching around the template structure (like putting it in /addons or /app and linking to the template in different ways, but without success. My problem is that ember never uses the template from the addon.
If the component within the addon has a different name, like foobar.hbs, I can call it without a problem.
I'm currently looking through the source code and docs, trying to make sense of this. Is this even accomplishable the way I imagine it?
Thanks a lot!
You'd have to create the component in your ember app which, initially, will mean the component renders as nothing as it's a brand new, empty component. Then you'd dig into your node_modules, find the component file and template and copy over what you'd need to work with.
Here's an example. While working with ember-cli-jsonapi-pagination, I need to customize the paginate-collection component:
I created the component in my application.
I looked at the source: https://github.com/BookingSync/ember-cli-jsonapi-pagination/tree/master/app
In components/paginate-collection/component.js I copied over the component code, but you should be able to import it as well.
In components/paginate-collection/template.hbs I modified the template as needed.

Render dynamic templates in Ember.js

I am new to Ember, so this might be a stupid question, but bear with me. Is there a specific reason one can't render templates with a dynamic string? Specifically, I push various objects to a controller variable like this:
this.controllerFor('application').get('popups').pushObject({
resource: article,
template: 'article'
});
And then try to render them:
{{#each popup in model}}
{{ render popup.template popup.resource }}
{{/each}}
This doesn't work in Ember as-is, since it expects a string as the template. I just patched this in my ember source in the renderHelper function:
if(name.value) name = name.value();
This makes sure that if the name comes from a property, it gets converted to a string correctly. It works perfectly fine. What is the reason Ember doesn't support this out-of-the-box? Am I missing something?
A little background for the stuff above: I want to open lots of different resources in popups on the page, but I want to keep the popups separated from the rest of the current route so I can show them on their own page if needed without duplicating code. My idea was that I push all open popups to a global array, and they are rendered at the bottom of the page (A bit like we do it at the moment without ember). Maybe there is a better way to do this that I missed!
You want to
Create a popup template independent of route
Pass data to template and render it any where
Right ? If yes there is a very good concept of component in Ember.js
Component is a small module with is separate from application. It only depends upon the data passed into it.
It can be reused in different portion without ever effecting each other. They are especially good to run third party plugins like qtip etc.
here is good article about use case of component.

Ember.js: How do I associate my component with a model?

I am new to Ember.js and am trying to figure out how to piece things together at this point. One component I built, since I need a re-usable "widget" to use across many portions of my application, is a "site nav" widget. Basically, it's almost like the buttons/links you see in StackOverflow when you open a new question titled: "Questions Tags Users Badges Unanswered". In my app, these links have a name and id associated with them on the server-side. I want to be able to use this navigation widget on multiple parts of my app and it should be as simple as putting:
{{site-nav}}
into a template. I got that part working just fine, but the navigation is currently hard coded in handlebars. My question is, for a component, where is the right place to retrieve/populate model data from the server? For a controller, we do it directly from the controller's route definition. The component is not associated with a router. In fact, it can be re-used, as mentioned before, in several parts of the app.
I want to be able to drop this component into templates and have it populated with modeled nav from the server which has the name/IDs of the navigation I need. Where is the best place to do this? I'm guessing I'll still extend from something like DS.Model, but I'm not entirely sure where/when/how to integrate this with the component. When do I create the model and invoke a .find() type call to the server to populate site-nav with data?
you can pass value to component Passing properties to component
via handlebars.
{{my-nav navlist=listfromserver}}
so the list from server is in our controller can be passed to the component

Categories