AlpineJS X-ref Binding to display HTML from another file - alpine.js

I am currently learning Alpine JS and trying to find examples of binding using x-ref ( As per to the Docs: https://github.com/alpinejs/alpine#x-ref )but there isn't many as it only became a feature late year year. I am just wondering could anyone provide an example on how to x-ref a variable so it can be used in a Fetch Method.
Currently I am not using x-ref and using x-html which is not rendering the HTML code for some reason, so I'm hoping by using x-ref it will work(?)
<div x-data="foo()" x-init="init()" >
<div>
<template x-for="foo in list" :key="foo.id">
<button
#click="activeTab = itemfooid"
x-text="foo.name"
x-ref="foo.name"
x-on:click="getHTML( item )"
>
</template>
<div x-ref="myxRef" x-show="activeTab === 0" x-html ="foo[0].name"> post </div>
</div>
Fetch Foo
function foo(){
activeTab: 0, // Set active tab to POST
list: [],
init(){
this.list = { id: 1, name: 'foo', code: 'null' },
}
}
getHTML( foo){
fetch('url/example.html')
.then(response => response.text() )
.then(html => {
if( foo.code=== undefined ){
foo.code= html
}
})
.catch( error => console.log ( error ) )
},
Example HTML:
<code language-php> $test = 1 <div x-if="country === undefined"> echo "Hey"; </div> return $test </code>
My code will only have the code brackets and the rest inside will be plain text.
Below is an example I found on which I'm trying to follow but that doesn't work either. https://laracasts.com/discuss/channels/javascript/laravel-alpinejs-fetch-and-x-ref
<div x-ref="test" class="window-content"></div>
<script>
function windowManager()
fetch('/frontend/blog')
.then(response => response.text())
.then(html => { this.$refs.test.innerHTML = html })
}
</script>

Related

React TypeError: orders.map is not a function

I'm a begginer in React. I'm trying to fetch an array of data about orders and that is working and then map it to display specific information about each order.
I'm getting TypeError: orders.map is not a function exception in my application.
Here's my code:
class Orders extends Component {
state = {
orders: []
};
componentDidMount() {
axios
.get("https://localhost:9090/orders")
.then(res => {
this.setState({ orders: res.data });
console.log(res.data);
});
}
render() {
const { orders } = this.state;
const orderList =
this.state.orders.length > 0 ? (
orders.map(o => {
return (
<div key={o.orderId}>
<p>
{o.isbn}
</p>
</div>
);
})
) : (
<div className="row p-5 m-5">
<div className="offset-sm-5 col-sm-2 text-center">
<span className="text-grey r">Loading...</span>
</div>
</div>
);
return <div className="container">{orderList}</div>;
}}
What's interesting, I have a similar code, that is working. The only difference is basically what it's fetching. Here's the code:
class BookList extends Component {
state = {
books: []
};
componentDidMount() {
console.log(this.props.match.params.search_term);
axios
.get("https://localhost:8080/search?searchTerm=" + search_term)
.then(res => {
this.setState({ books: res.data });
console.log(res.data);
});
}
render() {
const { books } = this.state;
const booksList =
this.state.books.length > 0 ? (
books.map(b => {
return (
<div key={b.isbn} className="card">
<div className="card-body">
<h5 className="card-title">
<Link to={"/details/" + b.isbn}>{b.title}</Link>
</h5>
<div className="card-subtitle text-muted">
{b.author} ({b.year}) /{" "}
<span className=" text-danger">{b.category}</span>
</div>
<p />
</div>
</div>
);
})
) : (
<div className="row p-5 m-5">
<div className="offset-sm-5 col-sm-2 text-center">
<span className="text-grey r">Loading...</span>
</div>
</div>
);
return <div className="container">{booksList}</div>;
}}
I can't find the difference that would cause that exception. It is an array in both cases.
Any suggestions?
EDIT:
here's the output of response data:
response data of order
response data of bokstore
From them images it looks like the orders are processed as plain text and not parsed to JSON. Check that your back-end specifies the required headers Content-Type: application/json so that axios will parse the data correctly.
Alternatively you could parse the text client-side with JSON.parse(res.data)

Find a matching value in Vue component

I have passed this collection (postFavourite) to my vue component via props.
[{"id":1,"user_id":1,"post_id":2,"created_at":"2018-07-24 09:11:52","updated_at":"2018-07-24 09:11:52"}]
How do I then check if any instance of user_id in the collection is equal to userId which is the current logged in user (also sent via props).
Tried
let pf = _.find(this.postFavourite, { "user_id": this.userId})
Keep getting undefined as the value of the pf variable even though this.userID is equal to 1.
New to JS and Vue.js so any help would be great.
Here is the vue component code.
<template>
<div>
<i v-show="this.toggle" #click="onClick" style="color: red" class="fas fa-heart"></i>
<i v-show="!(this.toggle)" #click="onClick" style="color: white" class="fas fa-heart"></i>
</div>
</template>
<script>
export default {
data() {
return {
toggle: 0,
}
},
props: ['postData', 'postFavourite', 'userId'],
mounted() {
console.log("Post is :"+ this.postData)
console.log("User id is: "+ this.userId)
console.log("Favourite Object is :" +this.postFavourite);
console.log(this.postFavourite.find(pf => pf.user_id == this.userId));
},
methods: {
onClick() {
console.log(this.postData);
this.toggle = this.toggle ? 0 : 1;
}
}
}
</script>
This is how I passed the props to vue
<div id="app">
<favorite :post-data="'{{ $post->id }}'" :post-favourite="'{{Auth::user()->favourite }}'" :user-id="'{{ $post->user->id }}'"></favorite>
</div>
I gave up on lodash and find and just messed around with the data in the chrome console to work out how to check the value I wanted.
Then I built a loop to check for the value.
If it found it toggle the like heart on of not leave it off.
This will not be the best way to solve this problem but I'm just pleased I got my first real vue component working.
<template>
<div>
<i v-show="this.toggle" #click="onClick" style="color: red" class="fas fa-heart"></i>
<i v-show="!(this.toggle)" #click="onClick" style="color: white" class="fas fa-heart"></i>
</div>
</template>
<script>
export default {
props: ['postData', 'postFavourite', 'userId']
,
data() {
return {
toggle: 0,
favs: [],
id: 0
}
},
mounted () {
var x
for(x=0; x < this.postFavourite.length; x++){
this.favs = this.postFavourite[x];
if(this.favs['post_id'] == this.postData) {
this.toggle = 1
this.id = this.favs['id']
}
}
},
methods: {
onClick() {
console.log(this.postData)
if(this.toggle == 1){
axios.post('favourite/delete', {
postid: this.id
})
.then(response => {})
.catch(e => {
this.errors.push(e)
})
}
else if(this.toggle == 0){
axios.post('favourite', {
user: this.userId,
post: this.postData
})
.then(response => {
this.id = response.data
})
.catch(e => {
this.errors.push(e)
})
}
this.toggle = this.toggle ? 0 : 1;
}
}
}
</script>
Where I pass my props.
<favorite :post-data="'{{ $post->id }}'"
:post-favourite="{{ Auth::user()->favourite }}"
:user-id="'{{ Auth::user()->id }}'"></favorite>
Thanks to all that tried to help me.
From just the code you provided, I see no issue. However lodash is not required for this problem.
Using ES2015 arrow functions
let pf = this.postFavourite.find(item => item.user_id === this.userId);
Will find the correct item in your array
You can read more about this function in the mdn webdocs
You can use find() directly on this.postFavourite like this:
this.postFavourite.find(pf => pf.user_id == this.userId);
Here is another way to do it that might help you as well.
[EDIT]
In order to use find() the variable needs to be an array, this.postFavourite is sent as a string if you didn't use v-bind to pass the prop thats what caused the error.
To pass an array or an object to the component you have to use v-bind to tell Vue that it is a JavaScript expression rather than a string. More informations in the documentation
<custom-component v-bind:post-favourite="[...array]"></custom-component>

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.

redux-form and react-select with options appearing as user types

I have a redux-form with a react-select. The expected behaviour is that, as I type in the select field, I call the redux action (by using OnInputChange). But I don't know how to call the action. The line that calls the action is commented in the snippet below, because it fails (this.props.getArtistSearch(value)). Any ideas of how to properly call the action as user types in?
class FormApplication extends React.Component {
submit(values) {
this.props.submitForm(values)
}
getArtist(value){
//this.props.getArtistSearch(value) --> props is undefined
console.log(value)
}
render() {
const { handleSubmit } = this.props
return (
<form className='content text padding-top-0' onSubmit={handleSubmit(this.submit.bind(this))}>
<div className='row adjust-form-row'>
<div className='col-md-6 last-lineup'>
<div className='row adjust-form-row'>
<div className='col-md-6'>
<div className='form-group'>
<Field
name='dl_artistname'
options={this.props.gap.artistSearch}
component={props => (
<Select
{...props}
name={props.name}
onInputChange={this.getArtist}
onChange={(value) => {
this.props.requestArtistInstance({id: value.dl_artistid })
return props.input.onChange(value != null ? value.dl_artistid : null)}
}
onBlur={() => props.input.onBlur(props.input.value)}
options={props.options}
//loadOptions={getOptions}
clearable={false}
cache={false}
backspaceRemoves={false}
valueKey='dl_artistid'
labelKey='dl_name'
value={props.input.value || ''}
isLoading={false}
disabled={false}
/>
)}
/>
</div>
</div>
</div>
</div>
</div>
</form>
)
}
}
const mapDispatchToProps = dispatch => ({
getArtistSearch: (text) => {
dispatch(getArtistSearch(text))
},
submitForm: (values) => {
dispatch(submitForm(values))
}
})
Going through your code, I noticed that the custom method you defined, getArtist was not bound to your React context so props will be undefined. Two possible approaches for this are:
1) bind it in the constructor method
constructor(){
super();
this.getArtist = this.getArtist.bind(this);
}
2) Alternatively, bind it in the Select component(Not ideal tho')
onInputChange={this.getArtist.bind(this)}

Testing divs exist with Jasmine,Webpack and vue.js

In my vue component I have code that conditionally renders a div:
<div v-if="successCriteria()" id="success">
<div class="row">
<div class="col-md-12">
<Commit-chart :data="chartOptions" ></Commit-chart>
</div>
</div>
</div>
<div v-else>
There has been an error with rendering.
</div>
</div>
and I am trying to test this using jasmine. For example, when the success criteria is met, the success div is present. here is my test:
describe('Graph Tests', () => {
const getComponent = (prop1,prop2) =>{
let vm = new Vue({
template: '<div><graph ref="graph" :label=prop1 :data=prop2></graph></div>',
components: {
graph,
},
})
return vm;
}
it('Renders correctly with valid props', () => {
const label = ['j', 'a' ,'c', 'k'];
const data=[1,2,3,4]
var vm = getComponent(label,data).$mount();
console.info(vm.$refs.graph.$el);
expect(vm.$refs.graph.$el.querySelector('success')).toBeTruthy();
});
});
}
When I log vm.$refs.graph.$el I get:
INFO: <!---->
in the console which I am very confused about. Can anyone help me get the div with id "success" ?
Thank you.
The selector for an id of "success" is '#success'. Or you can use getElementById.
However, the output from your program indicates the component is not rendering at all.

Resources