How to pass data from a component to an Instance in Vue - javascript

I am trying to get data from a component and pass it to a variable in my root Vue instance.
My Vue Instance:
new Vue({
el: '#root',
data: {
searchResultObject: ''
},
methods: {
//....
}
});
My Global Component:
Vue.component('user-container-component', {
props: {
prop: null
},
template: '#user-container-template',
data: function () {
return {
searchResultObject: ''
}
},
methods: {
dbSearch_method: function () {
var self = this;
$.ajax({
url: 'Home/LocalSearch',
type: 'GET',
success: function (response) {
self.searchResultObject = response;
},
error: function () {
alert('error');
}
});
}
}
})
Pressing a button in my UI triggers the dbSearch_method, that part works. I am wondering how I get the data to the searchResultObject in my instance, not the component?
HTML:
<button class="btn btn-link bold" v-on:click="dbSearch_method">{{item}}</button></li>
EDIT:
HTML:
<div id="root">
//...
<div id="collapse2" class="panel-collapse collapse">
<ul class="list-group">
<root-component v-for="item in customerObject"
v-bind:prop="item"
v-bind:key="item.id">
</root-component>
</ul>
</div>
</div>
//...
<script type="text/x-template" id="root-template">
<li class="list-group-item">
<div class="bold">
<button v-if="open" v-on:click="toggle" class="btn btn-link"><span class="glyphicon glyphicon-chevron-down" style="color: black"></span></button>
<button v-else="open" v-on:click="toggle" class="btn btn-link"><span class="glyphicon glyphicon-chevron-right" style="color: black"></span></button>
<button class="btn btn-link bold">{{prop.name}}</button>
</div>
<ul class="no-bullets" v-show="open">
<park-container-component v-bind:prop="prop.parks"/>
<admin-container-component v-bind:prop="prop.admins" />
<user-container-component v-on:search-results-fetched="addSearchResults($event)" v-bind:prop="prop.admins" />
</ul>
</li>
</script>
<script type="text/x-template" id="user-container-template">
<li class="list-group-item">
<div class="bold">
<button v-if="open" v-on:click="toggle" class="btn btn-link"><span class="glyphicon glyphicon-chevron-down" style="color: black"></span></button>
<button v-else="open" v-on:click="toggle" class="btn btn-link"><span class="glyphicon glyphicon-chevron-right" style="color: black"></span></button>Users
<button class="btn btn-primary btn-xs pull-right" data-toggle="modal" data-target="#inviteAdminModal">Add</button>
</div>
<ul class="no-bullets" v-show="open" v-for="item in prop">
<li><button class="btn btn-link bold" v-on:click="dbSearch_method">{{item}}</button></li>
</ul>
</li>
</script>
Script:
new Vue({
el: '#root',
data: {
//...
searchResultObject: ''
},
methods: {
//...
addSearchResults: function(data) {
alert('adding');
this.searchResultObject = data;
}
}
});
Vue.component('user-container-component', {
props: {
prop: null
},
template: '#user-container-template',
data: function () {
return {
open: false
}
},
methods: {
toggle: function () {
this.open = !this.open;
},
dbSearch_method: function () {
var self = this;
$.ajax({
url: 'Home/LocalSearch',
type: 'GET',
success: function (response) {
self.$emit('search-results-fetched', response);
},
error: function () {
alert('error');
}
});
}
}
})

As you said the component user-container-component is inside element with id #root, assming your html to be like this:
<div id="root">
<user-container-component></user-container-component>
</div>
in your user-container-component emit an event in the succss callback of your dbSearch_method ajax request like this:
Vue.component('user-container-component', {
props: {
prop: null
},
template: '#user-container-template',
data: function () {
return {
searchResultObject: ''
}
},
methods: {
dbSearch_method: function () {
var self = this;
$.ajax({
url: 'Home/LocalSearch',
type: 'GET',
success: function (response) {
this.$emit('search-results-fetched', response);
},
error: function () {
alert('error');
}
});
}
}
})
in your html setup an event listener on the user-container-component like this:
<div id="root">
<user-container-component #search-results-fetched="addSearchResults($event)"></user-container-component>
</div>
in your root instance add addSearchResults method:
new Vue({
el: '#root',
data: {
searchResultObject: ''
},
methods: {
addSearchResults(data){
this.searchResultObject = data;
}
}
});

You can emit the value as an event for parent to listen to
$.ajax({
url: 'Home/LocalSearch',
type: 'GET',
success: function (response) {
self.searchResultObject = response;
this.$emit('onSearchResult', response)
},
error: function () {
alert('error');
}
});
then in your parent you can fetch it by setup a listener
<user-container-component v-on:onSearchResult="parentListener"/>

For a big project, you can use vuex to manage the data.
Or you can just use eventbus to solve the same level component data transmission.here
For your situation, I think it should use $emit.
dbSearch_method: function () {
var self = this;
$.ajax({
url: 'Home/LocalSearch',
type: 'GET',
success: function (response) {
self.searchResultObject = response;
this.$emit('customEvent', response);
},
error: function () {
alert('error');
}
});
}
and in your root vue instance,you can use $on to listen the event fire.here

Related

Add/Remove button Ajax only show one

I have 2 buttons with this ajax and they both show on the page,how can i make it that only Add to favorites button is shown and when i click it the Remove From Favorites button takes it place ?
function Fav(gameId) {
var url = '#Url.Action("AddToCollection", "UserCollection")';
$.ajax({
url: url,
type: 'GET',
data: {
gameId: gameId,
},
});
};
function UnFav(gameId) {
var url = '#Url.Action("RemoveFromCollection", "UserCollection")';
$.ajax({
url: url,
type: 'GET',
data: {
gameId: gameId
},
});
};
<button class="btn-link" onclick="Fav(#Model.Id)"><i class="fa fa-heart"></i>Add To Collection</button>
<button class="btn-link " onclick="UnFav(#Model.Id)"><i class="fa fa-heart-broken"></i>Remove From Collection</button>
Try something like this.
DRY (Don't Repeat Yourself)
const urls = {
"AddToCollection": '#Url.Action("AddToCollection","UserCollection")',
"RemoveFromCollection": '#Url.Action("RemoveFromCollection","UserCollection")'
}
function Fav(gameId, action) {
$.ajax({
url: urls[action],
type: 'GET',
data: {
gameId: gameId,
},
});
};
$(function() {
const whichButton = "AddToCollection"; // set which one to show here using whatever method
$(".btn-link[data-action="+whichButton+"]").show();
$(".btn-link").on("click", function() {
Fav(this.dataset.id, this.dataset.action)
$(this).siblings().hide();
});
});
.hide { display: none; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="favDiv">
<button class="btn-link hide" data-action="AddToCollection" data-id=""><i class="fa fa-heart"></i>Add To Collection</button>
<button class="btn-link hide" data-action="RemoveFromCollection" data-id=""><i class="fa fa-heart-broken"></i>Remove From Collection</button>
</div>
This is the final result that i was looking for
const urls = {
"AddToCollection": '#Url.Action("AddToCollection","UserCollection",new { gameId = Model.Id })',
"RemoveFromCollection": '#Url.Action("RemoveFromCollection","UserCollection",new { gameId = Model.Id })'
}
function Fav(gameId, action) {
$.ajax({
url: urls[action],
type: 'GET',
data: {
gameId: gameId,
},
});
};
$(function() {
const whichButton = "AddToCollection"; // set which one to show here using whatever method
$(".btn-link[data-action=" + whichButton + "]").show();
$(".btn-link").on("click", function() {
Fav(this.dataset.id, this.dataset.action)
$(this).siblings().hide();
$(this).siblings().show();
$(".btn-link[data-action=" + whichButton + "]").hide();
});
});
.hide {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="favDiv">
<button class="btn-link hide" data-action="AddToCollection" data-id=""><i class="fa fa-heart"></i>Add To Collection</button>
<button class="btn-link hide" data-action="RemoveFromCollection" data-id=""><i class="fa fa-heart-broken"></i>Remove From Collection</button>
</div>

Passing data to an array in Vue.js

I'm sure it's something simple, but I can't get this to work. I've read the documentation and other sources, but I am just not understanding. I simply want to pass data that I retrieve with ajax to an empty array. I've ensured that the data is indeed successfully coming from the server, but it does not appear to get assigned to UserArticles, and does not update the DOM. What am I missing. Here's my code:
Component:
Vue.component('article-selection', {
props: ['articles'],
template: '<div> <p>{{articles.title}}</p> </div>'
})
Vue:
var Article = {};
var UserArticles = [];
var vm = new Vue({
el: '#createNewArticle',
data: {
Article: Article,
UserArticles: UserArticles
},
computed: {
isNewArticle: function () {
return this.Article.ArticleIdentification.Id.length < 5
}
},
created: function(){
this.getUserArticles();
},
methods: {
setUserId: function (id) {
//code
},
createNewArticle: function (msg) {
//code},
getUserArticles: function () {
$.ajax({
method: "GET",
url: "/api/Article/GetUserArticles"
}).done(function (rData, status, jq) {
UserArticles = rData;
toastr.success('', 'Retrieved User Articles');
}).fail(function (rData, status, error) {
var result = $.parseJSON(rData.responseText);
toastr.warning(result.messages, 'Retrieve User Articles')
});
}
}
})
HTML:
<div class="row" id="createNewArticle" >
<div class="col-sm-12">
<!--Create Initial article-->
<div class="row" v-if="true">
<div class="col-sm-12 text-center">
<div>Passed: {{Article.UserId}}</div>
<div class="form" style="display: inline-block;" id="newArticleForm">
<div class="form-group">
<label for="ArticleName">Article Title</label>
<input type="text" class="form-control" id="ArticleTitle"
name="ArticleTitle" v-model="Article.ArticleIdentification.Title" /><br />
<p>{{Article.ArticleIdentification.Title}}</p>
<button class="btn btn-sm" v-on:click="createNewArticle('hey hey')">
Create New Article
</button>
</div>
</div>
</div>
<div class="col-sm-12">
<!--COMPONENT HERE--!>
<article-selection v-for="(artId, index) in UserArticles"
v-bind:key="artId.id"
v-bind:index="index"
v-bind:articles="artId"></article-selection>
</div>
</div>
</div>
Try writing the method like this
$.ajax({
method: "GET",
url: "/api/Article/GetUserArticles"
success: function (data) {
UserArticles = data;
},
error: function (error) {
alert(JSON.stringify(error));
}
})
}
I had to use an arrow function in my ajax code inside of the done function as well as add the this keyword. Note the difference:
getUserArticles: function () {
$.ajax({
method: "GET",
url: "/api/Article/GetUserArticles"
}).done((rData, status, jq) => {
this.UserArticles = rData;
toastr.success('', 'Retrieved User Articles');
}).fail(function (rData, status, error) {
var result = $.parseJSON(rData.responseText);
toastr.warning(result.messages, 'Retrieve User Articles')
});
}

Clear jeasyui form fields after successful submit

I'm using a jeasyui form, inside a xoops module, in which I'm trying to clear all the form fields once the data has successfully submitted.
I've already consulted this question, but it didn't solve the problem in my case.
My HTML:
<div class="easyui-panel" title="Capture Reqs" style "width:100%;
max-width:600px; padding:30px 60px;">
<form action = "captureReqs_Save.php" id ="ff" class = "easyui-form"
method ="post" data-options = "novalidate:true">
<div style="margin-bottom:20px"> Area <br>
<input id="idArea" class="easyui-combobox" style="width:260px" name="idArea"
data-options="
url:'areasJson.php?idZona=<?php echo $idZone; ?>',
label:'Area:',
valueField: 'id',
textField: 'desc',
required:true
">
</div>
<div style="margin-bottom:20px"> Material
<input id="IdMaterial" class="easyui-combobox" style="width:100%"
name="IdMaterial" data-options="
loader: myloader,
mode: 'remote',
valueField: 'code',
textField: 'desc',
required:true
">
<div style="margin-bottom:20px"> Qty
<input class="easyui-textbox" name="quantity" style="width:100%"
data-options="label:'Qty:',required:true, validType:'number'">
</div>
<div style="margin-bottom:20px">
</form>
<div style="text-align:center;padding:5px 0">
<a href="javascript:void(0)" class="easyui-linkbutton"
onClick = "submitForm()" style="width:80px"> Submit</a>
<a href="javascript:void(0)" class="easyui-linkbutton"
onClick = "resetForm()" style = "width:80px"> Clear </a>
</div>
</div>
Script:
<script>
var myloader = function (param, success, error) {
var q = param.q || '';
if (q.length <= 2) {
return false
}
$.ajax({
url: 'materialJson.php?idArea=' + $('#idArea').combobox('getValue'),
dataType: 'json',
data: {
q: q
},
success: function (data) {
var items = $.map(data, function (item, index) {
return {
code: item.code,
desc: item.desc
};
});
success(items);
},
error: function () {
error.apply(this, arguments);
}
});
}
function submitForm() {
$('#ff').form('submit', {
onSubmit: function () {
return $(this).form('enableValidation').form('validate');
}
});
}
function resetForm() {
$('#ff')[0].reset();
}
</script>
Try calling resetForm. I converted to use promise style ajax and added resetForm
var myloader = function (param, success, error) {
var q = param.q || '';
if (q.length <= 2) {
return false
}
$.ajax({
url: 'materialJson.php?idArea=' + $('#idArea').combobox('getValue'),
dataType: 'json',
data: {
q: q
}
}).then(function (data) {
var items = $.map(data, function (item, index) {
return {
code: item.code,
desc: item.desc
};
});
success(items);
}).fail(function () {
error.apply(this, arguments);
});
}
function submitForm() {
$('#ff').submit(function () {
if ($(this).form('enableValidation').form('validate')) {
$.post($(this).attr('action'), $(this).serialize(), function (response) {
clearForm();
});
}
return false;
});
}
function resetForm() {
$('#ff')[0].reset();
}

How to set the id for the new created item with Knockout

The problem is that I cannot update a new created item, because on the server I receive no Id.
I am trying to learn Knockout, and I am not able to find a way to provide the Id to new created items.
I have an object with Id, and Name, using knockout I can make all Crud operations, but, after inserting a new item, if I try to change his name I am not able because that item has no Id value.
My question is: Every time when I add a new item I need to get a fresh collection of items back to the view, and rebind the view?
or, there is a way to another way to provide the Id to the new inserted items?
Here is my code:
function Person(id, name) {
var self = this;
self.Id = ko.observable(id);
self.nume = ko.observable(name);
}
function PersonVm() {
var self = this;
self.Persons = ko.observableArray([]);
self.newPerson = ko.observable(new Person())
self.isModificare = false;
self.addPerson = function () {
if (!self.isModificare) {
$.ajax("/Person/AddPerson", {
data: ko.toJSON({ Person: self.newPerson }),
type: "post", contentType: "application/json",
success: function (result) { alert(result.mesaj); }
});
} else {
$.ajax("/Person/UpdatePerson", {
data: ko.toJSON({ Person: self.newPerson }),
type: "post", contentType: "application/json",
success: function (result) { alert(result) }
});
}
self.isModificare = false;
if (!self.isModificare) self.Persons.unshift(self.newPerson());
self.newPerson(new Person());
}
self.removePerson = function () {
$.ajax("/Person/DeletePerson", {
data: ko.toJSON({ Person: self.newPerson }),
type: "post", contentType: "application/json",
success: function (result) { alert(result) }
});
self.Persons.remove(self.newPerson());
self.newPerson(new Person());
}
self.ModificaPerson = function (person) {
self.newPerson(person);
self.isModificare = true;
}
$.getJSON("/Person/GetPersons", function (allData) {
var mapPerson = $.map(allData, function (item) { return new Person(item.Id,item.Name) });
self.Persons(mapPerson);
});
}
ko.applyBindings(new PersonVm());
Edit:
This is the view:
<div class="input-group">
<input type="text" class="form-control" data-bind="value: newPerson().name">
<span class="input-group-btn">
<button class="btn btn-default" data-bind="click:addPerson">
<span class="glyphicon glyphicon-plus-sign" style="color:green"></span>
</button>
</span>
<span class="input-group-btn">
<button class="btn btn-default" data-bind="click:$root.removePerson">
<span class="glyphicon glyphicon-trash" style="color:red"></span>
</button>
</span>
</div>
<ul data-bind="foreach: Perons" class="list-group" id="content">
<li class="list-group-item" data-bind="text: name,click:$root.ModificaPerson"></li>
</ul>
Two steps to get what you want:
Ensure that your "Person/AddPerson" Web service return the ID of the created object.
Change your update method so that it sets an ID on the newPerson property:
$.ajax("/Person/AddPerson", {
data: ko.toJSON({ Person: self.newPerson }),
type: "post", contentType: "application/json",
success: function (result) {
self.newPerson().Id(result.Id);
}
});
Note that the above code supposes that your services returns a JSON object with an ID property named 'Id'.

React State change is not Rendering

I'm fairly new to React and I'm having an issue where my initial state is rendering, but when the state is changed via AJAX call (successful) is not causing the function to render again. So what happens is the 'getInitialState' sets a static list of categories and 'componentDidMount' gets a new list from my API. The call executes correctly and triggers a success, so I don't know why the dropdown isn't updating.
var Dropdown = React.createClass({
getInitialState: function() {
return {
listVisible: false,
display: ""
};
},
select: function(item) {
this.props.selected = item;
},
show: function() {
this.setState({ listVisible: true });
document.addEventListener("click", this.hide);
},
hide: function() {
this.setState({ listVisible: false });
document.removeEventListener("click", this.hide);
},
render: function() {
return <div className={"dropdown-container" + (this.state.listVisible ? " show" : "")}>
<div className={"dropdown-display" + (this.state.listVisible ? " clicked": "")} onClick={this.show}>
<span>{this.props.selected.name}</span>
<i className="fa fa-angle-down"></i>
</div>
<div className="dropdown-list">
<div>
{this.renderListItems()}
</div>
</div>
</div>;
},
renderListItems: function() {
var categories = [];
for (var i = 0; i < this.props.list.length; i++) {
var category = this.props.list[i];
categories.push(<div onClick={this.select.bind(null, category)}>
<span>{category.name}</span>
<i className="fa fa-check"></i>
</div>);
}
return categories;
}
});
var GridFilter = React.createClass({
getInitialState: function() {
return {categoryList: [{
name: "Cat1",
value: "#F21B1B"
}, {
name: "Cat2",
value: "#1B66F2"
}, {
name: "Cat3",
value: "#07BA16"
}] };
},
getCategories: function() {
var nextPage = 1; //increase the page count
ajax_url = "http://127.0.0.1:8200/api/categories/";
ajax_type = "GET";
ajax_data = {};
$.ajax({
url: ajax_url,
type: ajax_type,
contentType: 'application/x-www-form-urlencoded',
data: ajax_data,
dataType: 'json',
success: function(data) {
this.setState({
data: this.state.categoryList,
});
//loading("off");
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
}, //end function
componentDidMount: function() {
this.getCategories();
},
render: function() {
return (
<div id="filter-bar" className="stamp">
<Dropdown list={this.state.categoryList} selected={this.state.categoryList[0]} />
<p className="filter-select">Categories <i className="fa fa-angle-down"></i></p>
<p className="filter-select">Type <i className="fa fa-angle-down"></i></p>
<p className="filter-text">Filters:</p>
</div>
);
}
});
if youre trying to change the categoryList state with your incoming data you need to change your set state to
this.setState({
categoryList: data,
});
what youre currently doing is adding a state with key data (even though there is no data key in your getInitialState function). and since youre not using this.state.data anywhere, nothing is changing, and so your ui does not appear to be updating

Categories