AngularJS: Objects and data available from parent component? - javascript

I am working on a large web application written using AngularJS. Unfortunately, I only know Angular well from version 2, so I have a question about data passing. I need to develop a component that makes use of an existing component (whose code is really long and complex) and dynamically shows results based on the existing component. So I have a template of my component like this (my-component.html):
<div>
<ng-transclude></ng-transclude>
</div>
<!-- Here I have to write the logic to dynamically display the information arrived with ng-trasclude -->
The template in which I use my component will then look like this:
<my-component>
<component-made-by-other-developers
data1="$ctrl.CertainTypeOfObject"
data2="anotherTypeOfObject"
></component-made-by-other-developers>
</my-component>
The question is: how do I use the data (in the example data1 and data2) of the component developed by other developers within MY component (i.e. in the my-component.js and my-component.html files)? My problem is that the ng-transclude directive seems to give no access to the data of the other components (passed in input) if I want to use them in my own component. The question is: how can I use these data in my component (both template and controller)?

Try using ng-include inside your component and pass the data by using onload
Your code should look something like this:
<div ng-include="otherDeveloperComponent.html" onload="passedData=$ctrl.CertainTypeOfObject; source='myComponent'" ng-if="true">

Related

Vue CLI plugin passing dynamic JS variables into props

I'm using version 4.5 of the Vue CLI plugin and have built a component that accepts a title as a prop. I've then built my component into a web component and have included it into my HTML web page (that isn't a Vue JS project)
I'm trying to now update the props of my component in my HTML & JS project dynamically, and initially thought I could use a JS data attribute and update the data attribute prop as this would work, along with a watcher in my component, but this didn't update with the new dynamic value.
I've read a little online, and have implemented a suggestion, but can't seem to get my component to update with the JS variable, what am I doing wrong or what's the workaround?
<script>
var creditModalPluginTitle = 'Foo Bar'
</script>
<div style="margin-bottom:10em;">
<vue-les-creditreport :title="creditModalPluginTitle"></vue-les-creditreport>
</div>
Inside of my Credit Report plugin I'm outputting title but it's not updating with the value from creditModalPluginTitle.
I can't be the only person with this problem.
The markup shown looks like it's intended for the non Vue page, where you included your Vue component (vue-les-creditreport). This markup uses Vue syntax for data binding (i.e., the v-bind directive in :title="creditModalPluginTitle"), but that only works within Vue templates.
You would need to set the component's title property using vanilla JavaScript:
<div style="margin-bottom:10em;">
<vue-les-creditreport id="myElem"></vue-les-creditreport>
</div>
<script>
document.getElementById('myElem').title = creditModalPluginTitle
</script>

Achieving simple tasks with vue (Laravel)

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.

How to use #Input in <router-outlet></router-outlet>

I am new in angular 4. I found out that there is a way in angular to pass data from the parent component to the child component using #Input just like following:
<child [dataToPass]="test"></child>
My question is how to do the same thing using a router. In the router, there is no child definition like <child></child>; it only has <router-outlet></router-outlet>, so how do I pass data using #Input?
The only way is to use a shared service or use Ngrx.
Component added by the router is added as sibling to
and does not replace it
What you want to achieve is to prefetching data from component to another when transferring via router.
I highly suggest using a resolver to load the data as explained here.
This will allow you to not only pass data via the router but also will the second component/page wait till the data is fetched so you don't run in a case of "my site is loaded but no data is displayed" ;) if you need further help with the implementation feel free to comment on this and share some code in your question.

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.

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