Issue with transitioning to UI-router child state from parent state - angular-ui-router

I've tried looking at other threads for help in this regard but to no avail. I understand I'm putting into use nested states and also tried absolute/relative routes but it does not transition to attributeDefinition state from searchResults. I'm using UI Router for state transition with the following files ...
<!-- index.html page -->
<div ai-body>
<!-- AngularUI View Pane -->
<div class="ai-content content" id="ai-content" ui-view></div>
</div>
//index.router.js: Routes
.state('searchResults', { //Parent state
url: "/searchResults/{app}?keyword",
templateUrl: "app/searchResults/searchResults.html",
ncyBreadcrumb: { label: 'Search Results' }
})
//Attribute Definition
.state('searchResults.attributeDefinition', { //child state
url: "/attributeDefinition/{action}",
templateUrl: "app/attributeDefinition/attributeDefinition.html",
ncyBreadcrumb: { label: 'Create Attribute Definition' }
})
<!-- searchResults state -->
<a type="button" class="btn btn-primary" ui-sref=".attributeDefinition({action: 'create'})">
Create new definition
</a>

I was able to resolve loading a nested state in the unnamed ui-view of the parent state with the following configuration of $stateProvider. It's making use of targeting unnamed view (as opposed to relative) using the 'views' attribute. Might look straight-forward but I did not find the online documentation easy to interpret nor were any online examples offering this solution. Refer documentation for more information, here [ http://bit.ly/VLKhGg ] -
$stateProvider
//Parent state
.state('searchResults', {
url: "searchResults/{app}?keyword",
views: {"#" : { url: "/searchResults/{app}?keyword",
templateUrl: "app/searchResults/searchResults.html" } }
})
//Child state
.state('searchResults.attributeDefinition', {
url: "/attributeDefinition/{action}",
parent: 'searchResults',
views: {"#" : { url: '/attributeDefinition/{action}',
templateUrl: "app/attributeDefinition/attributeDefinition.html" } }
})

Related

Laravel Nova | Arrow functions | computed property not working in Tool.vue

I have a computed property that is not working correctly. When reading the docs this is how it should be done for Vue 2.x. The code i have:
<template>
<div>
<button :disabled="isDisabled">Import configurator data</button>
<input class="input" type="file" id="file" v-on:change="setFile">
</div>
</template>
<script lang="js">
export default {
data: () => {
return {
importDisabled: true,
}
},
computed: {
isDisabled() {
return this.importDisabled;
},
},
methods: {
setFile: (e) => {
this.importDisabled = false;
},
}
}
</script>
Expected behaviour: Button enables when a file is selected.
Actual behaviour: Button stays disabled.
What am i missing here? A console.log within the isDisabled() methods shows it is only called once. It is not called after importDisabled changes.
Other info:
vue 2.6.12
laravel nova
Also note: Vue tools does not detect a Vue component in the inspector. But the Vue behaviour is working when loading the tool.
It seems arrow functions are bound to the parent context. That was the reason my code did not work. this is then not bound to the Vue instance but the parent (Window) which causes it not to work.
Wrong:
setFile: (e) => {
this.importDisabled = false;
},
Right:
setFile: function() {
this.importDisabled = false;
},
More information:
https://codingexplained.com/coding/front-end/vue-js/using-es6-arrow-functions-vue-js

Vue this.$emit('eventName') events in component A are not triggering this.$on('eventName', callbackFunc) in component B, have I misplaced the handler?

Basically, I have components that trigger an event when they are created and a specialized "counter" component that counts the created components, this second component exists in parallel to the first. However when I try to run the app, the counter component only counts itself, it seems to only be detecting the creation event being triggered there.
I've tried to move the this.$on() operation to other lifecycle hooks, such as mounted() but that failed.
Component A:
Vue.component('counter-component',{
template: `
<div class="card">
<div class="card-header">
Components:
</div>
<div class="card-body">
<p>Count: {{ totalCount }}</p>
<p>Enabled Count: {{ totalEnabledCount }}</p>
<p>Diabled Count: {{ totalDisabledCount }}</p>
</div>
</div>`,
created(){
this.$on('component-created', this.componentCreated),
this.$on('component-disabled', this.componentDisabled),
this.$on('component-enabled', this.componentEnabled),
this.$emit('component-created', 'counter-component');
},
data(){
return {
totalCount: 0,
totalDisabledCount: 0,
}
},
computed: {
totalEnabledCount(){
return this.totalCount - this.totalDisabledCount;
},
},
methods: {
componentCreated(data){
this.totalCount++;
},
componentDisabled(data){
this.totalDisabledCount++;
},
componentEnabled(data){
this.totalDisabledCount--;
}
}
});
Component B:
Vue.component('regular-component',{
template: `
<div class="my-2">
<div class="card" v-show="isVisible">
This is visible
</div>
<div class="card" v-show="!isVisible">
This is invisible
</div>
</div>`,
created(){
this.$emit('component-created', 'message-component');
},
data: () => {
return ({
isVisible: true,
});
},
methods: {
toggleVisibility(){
this.isVisible = !this.isVisible;
if(this.isVisible){
this.$emit('component-enabled','message-component');
} else {
this.$emit('component-disabled','message-component');
}
}
},
});
I was expecting both components to be counted, unfortunately only the component that contains the handler.
It seems you're expecting there to be a global event bus that you can emit and subscribe to.
This is not the case by default in Vue, instead Vue uses a strictly hierarchical approach where events are emitted from child to parent and properties are passed from parent to child. Interaction between sibling components is not intended by default.
A correct approach for your case would be to introduce a parent component that listens for the event, holds the totalCount as state and passes it as property to your counter-display component:
<parent>
<regular-component v-on:component-created="totalCount++"/>
...
<counter-component v-bind:count="totalCount"/>
</parent>
Use please vuex. It helps you to decrease the quantity of spaghetti code.
https://vuex.vuejs.org/

How to transfer data between components placed in different views

I have two compoennts placed in one the same view.
#extends('layouts.app')
#section('content')
<bus></bus>
<bus2></bus2>
#endsection
I want to pass data (name) from one component to other one after clicking button. To do that I' using $emit function.
/// bus component
<template>
<div>
<p> Name Bus 1{{name}}</p>
<input type="button" #click="setName()" value="s"/>
</div>
</template>
<script>
export default {
created() {},
data: function() {
return {
name: "Volvo"
};
},
methods: {
setName: function(id) {
this.$root.$emit("sname", this.name);
}
},
props: []
};
</script>
///bus 2 component
<template>
<div>
<p> Name bus 2{{name}}</p>
</div>
</template>
<script>
export default {
created() {
this.$root.$on("sname", data => {
this.name = data;
});
},
data: function() {
return {
count: 0,
name: ""
};
},
methods: {}
};
</script>
Everything works fine. Name is transfered from bus to bus2. The problem exists when I place bus2 in different view - data are not transfered but code is the same. How can I transfer data between components placed in different views
Try using Vuex to specify your app state, and mutate this when it's necessary.
Vuex states are accessible from every components using this.$store or $store.

Laravel router-link works only the first time

I am trying to fetch results from database in News.vue, and display them in Topnews.vue. I have two links fetched. When I click link1, it shows up the Topnews.vue template with everything working as intended, however, if i click link2, nothing happens, except for that the URL changes, but the template does not show up the result. If i refresh the page and click link2 or click on the navbar, then link2, it shows up, and same, clicking then link1, changes the URL, but doesnt show up. I'm really stuck on that and I'd be really glad if you help me out on that issue. Hope you understand.
News.vue
<template id="news">
<div class="col-sm-5">
<div class="cars" v-for="row in filteredNews" >
<div class="name" >
<p class="desc_top_time">{{row.created_at}}</p>
<span class="last_p"> {{row.category}}</span>
<h3 style="margin-bottom:-4px; font-size: 16px;">
<router-link class="btn btn-primary" v-bind:to="{name: 'Topnews', params: {id: row.id} }">{{row.title}}</router-link></h3>
</div></div></div>
</template>
<script>
export default {
data: function() {
return {
news: [],
}
},
created: function() {
let uri = '/news';
Axios.get(uri).then((response) => {
this.news = response.data;
});
},
computed: {
filteredNews: function() {
if (this.news.length) {
return this.news;
}
}
}
}
</script>
Topnews.vue
<template id="topnews1">
<div class="col-sm-7">
<div class="cars">
<img :src="topnews.thumb" class="img-responsive" width=100%/>
<div class="name" ><h3>{{ topnews.title }}</h3>
<p>
<br>{{ topnews.info }}<br/>
</p>
</div></div></div>
</template>
<script>
export default {
data:function(){
return {topnews: {title: '', thumb: '', info: ''}}
},
created:function() {
let uri = '/news/'+this.$route.params.id;
Axios.get(uri).then((response) => {
this.topnews = response.data;
});
}
}
</script>
Like GoogleMac said Vue will reuse the same component whenever possible. Since the route for both IDs use the same component Vue will not recreate it, so the created() method is only being called on the first page. You'll need to use the routers beforeRouteUpdate to capture the route change and update the data.
in TopNews.vue:
export default {
data:function(){
return {topnews: {title: '', thumb: '', info: ''}}
},
beforeRouteEnter:function(to, from, next) {
let uri = '/news/'+ to.params.id;
Axios.get(uri).then((response) => {
next(vm => {
vm.setData(response.data)
})
});
},
beforeRouteUpdate: function(to, from, next) {
let uri = '/news/'+ to.params.id;
Axios.get(uri).then((response) => {
this.setData(response.data);
next();
});
},
methods: {
setData(data) {
this.topnews = data
}
}
}
If you click a link referring to the page you are on, nothing will change. Vue Router is smart enough to not make any changes.
My guess is that the IDs are messed up. If you are using Vue devtools you will be able to easily see what data is in each link. Are they as you expect.

Kendo Ui ReferenceError in dynamic created form

I am creating dynamic forms using remote server information.. My code is
$.ajax({
url: xxx.php',
data: {
EXTAPP_ID: extappId,
OBJECT_NAME: sessionStorage.getItem('ssObjectName')
},
type: 'GET',
crossDomain: true,
dataType: 'jsonp',
success: function (model) {
console.log(model);
obsRecordFields = kendo.observable(model);
// bind the model to the container
kendo.bind($("#recordDetailView"), obsRecordFields);
kendo.init($("#Field1"));
}
});
the template which is generating the form fields is
<script id="fieldsTemplate" type="text/x-kendo-template">
<li>
<label data-bind="attr: { for: name}, text: label"></label>
# if (get("fieldtype") == "input") {#
<input data-bind="value: value, attr: { type: type, name: name}" # if (get("required")) {# required #} # />
#}else{#
<select id="name" data-role="dropdownlist" data-bind="source: options, value: value, attr: { type: type, name: name}" data-text-field="option_value" data-value-field="option_id" />
#}#
</li>
</script>
my problem is
when I open the page the first time it returns an error in console log saying "Uncaught ReferenceError: option_id is not defined " when I refresh the same page and all the related function again, it is working
I found the problem.
I made the ajax called inside the function that was triggered by data-init. The order of the events are
bind view model
beforeShow
init
show
So it started working when I triggered the function on data-show.
Thank you Spike for your very useful post (http://codingwithspike.wordpress.com/2012/12/31/kendo-mobile-gotchas-tips-tricks/) which helped to solve the problem.

Resources