I know that I can change the value of a vue data value from within a method by using this.variable_name. But when I'm trying to do this from within a method with a sub-method (because I'm making an ajax request) I am getting an undefined error.
I have something like
var myvue = new Vue({
name: "MyVue",
el: '#my-vue-id',
data: {
fields: field_list // this is set in another js method elsewhere
},
methods: {
reject: function (index, objectid) {
if (confirm("Are you sure?")) {
$.get("/reject/" + objectid, function (data) {
if (data.success == true) {
$("#" + objectid).fadeOut(400, function() {
this.field_list.splice(index, 1);
});
} else {
alert('Failed to delete.');
}
});
}
}
}
});
I also tried setting var self = this; within the $.get method, then trying to splice self.field_list but in both cases I get an error Cannot read property splice of undefined
EDIT since I may have been unclear-- the field_list is being populated. If I were to do this.field_list.splice outside the ajax function, it works fine. The issue is just how to access external scope from with the vue methods.
A callback function does not get your Vue instance as its context (this) when it is called. Use arrow functions for your callbacks, or save this to a variable and use that.
You need to do the var self = this; outside of the $.get method (before it) as within the $.get method you have a different scope, and that is the root of the problem. Then within the $.get method use self.field_list.splice(index, 1);
Related
I have a class I am using for creating CRUD Objects for my site.
It stores the form and table paths for adding, listing, editing and deleting the data, as well as reloading your view with ajax after each edit.
Here is my class definitions:
class CRUDObj{
constructor(containerSel, links) {
this.links = links;
this.containerSel = containerSel;
this.formCallBack = function(){};
}
setActive(obj_id){
$.post(this.links.editURL+'?'+obj_id, {status:"active"}, this.reload);
}
reload(returnData){
this.formCallBack(returnData);
this.formCallBack = function(){};
if($(this.containerSel).length > 0){
ajaxLoad(this.links.listURL, $(this.containerSel));
}
}
}
A basic instance of initializing it:
var contactObj = new CRUDObj('#contacts', {
editURL: '/contact.edit.php',
listURL: '/contacts.list.php',
});
contactObj.formCallBack = function(){
console.log('Custom Reload Callback');
};
The problem appeared when I tried to add the callback, so that I could run a custom function during the refresh.
Running contactObj.setActive(); works properly, and my refresh function is called after the form submits, but when it hits my callback I get:
Uncaught TypeError: this.formCallBack is not a function
Calling it manually contactObj.refresh(); works smoothly.
How can I pass this callback function through better?
The problem is that you're passing method as function, so you loose this context. this will be window object or undefined (if using strict mode):
You need this:
var self = this;
lightboxForm(this.links.editURL+'?'+obj_id, function(x) { self.reload(x) });
or using ES6
lightboxForm(this.links.editURL+'?'+obj_id, x => this.reload(x));
or using bind to return function with given context:
lightboxForm(this.links.editURL+'?'+obj_id, this.reload.bind(this));
I have been trying to execute a function as follows, but am not succeeding.
var leagueSelect = "allLeagues";
loadTable("#loadLeaguesTable","php/leagueTable.php",'leagueSelect',leagueSelect);
The loadTable function:
function loadTable(tableDiv, tableURL, tableType, tableVal){
$.post(tableURL,{tableType:tableVal},function(data){
$(tableDiv).append(data);
});
}
I'm trying to send the values in the post in this format: { leagueSelect: leagueSelect }.
If I hard-code leagueSelect into my function in place of the tableType parameter in the $.post function, it works.
How am I supposed to send 'leagueSelect' properly in my function call?
I'm thinking the data[key] = value method but I didn't get that working either.
Thanks.
When you assign the variable you're actually creating a new object with the property tableType set to whatever the tableVal value is.
Instead you need to use the object[key] = val; syntax or pass the post data in directly like this:
var leagueSelect = "allLeagues";
loadTable("#loadLeaguesTable", "php/leagueTable.php", { leagueSelect: leagueSelect });
function loadTable(tableDiv, tableURL, postData) {
$.post(tableURL, postData, function(data) {
$(tableDiv).append(data);
});
}
From within my webpage I am creating an object and trying to call a dynamically set function from within it. The dynamic function however, isn't being executed.
Here is a subset of the Object:
var LightBoxLogin = {
DialogBox: null,
SuccessFunction: null,
..........
Login: function(){
console.log(LightBoxLogin.SuccessFunction) // Displays "TestSubmit()"
LightBoxLogin.SuccessFunction(); // does nothing, should alert the page
}
}
LightBoxLogin.SuccessFunction is set with:
function SuperLightbox(functOnSuccess)
{
LightBoxLogin.SuccessFunction = functOnSuccess;
if(IsLightboxNeeded())
{
LightBoxLogin.Login();
}
else{
alert("Not needed");
}
}
And called like:
function TestSubmitHandler ()
{
SuperLightbox(TestSubmit);
}
function TestSubmit ()
{
alert('TEST SUBMIT ALL CAPS');
}
Let me know if im missing anything.
I just need to execute the function passed as a parameter initially.
Instead of the line
SuperLightBox(TestSubmit);
Use the function name as a String instead:
SuperLightBox("TestSubmit");
This means in the Login:function() this line:
LightBoxLogin.SuccessFunction();
Will be replaced with:
window[LightBoxLogin.SuccessFunction]();
This yields the results I was looking for, but beware; it only works if the desired function is accessible globally in the page.
I have an UserApplications object wich queries the server for a list of applications the user is registered to looking like this:
data.factory('UserApplications', function($resource){
return $resource('/users-rs/api/getapplications/:locale',{},{
query: {method: 'GET', params: {locale: 'locale'}, isArray: true}
});
});
I call it in another service and want to save the data as a JSON string using the angular-localstorageservice module (https://github.com/grevory/angular-local-storage) which is passed to the constructor of the service like this:
function UserService(UserInfoData, localStorageService, UserApplications){
this.UserInfoData = UserInfoData;
this.localStorageService = localStorageService;
this.userApplications = UserApplications;
}
When I give a callback function to the $resource.query() function and wrap it with $.proxy I keep getting this.localstorag is undefined, when I debug it this is a reference to window. So not exactly the behaviour I expected.
Is there any other way to pass 'this' or a reference to the object to the callback function?
I've allready tried with creating a variable with a reference to this but it doesn't do the trick either :/
UserService.prototype.getUserApplications = function(){
var locale = this.getUserinfoLocale();
var applications = this.localStorageService.get(Constants.key_applications+locale);
if(applications !== null){
return JSON.parse(applications);
} else {
return this.userApplications.query({locale: locale}, $.proxy(function(data, locale){
this.localStorageService.add(Constants.key_applications+locale, JSON.stringify(data));
}), this);
}
};
I think you missed the comma position and is sending "this" to userApplications' query method, not jQuery's proxy one.
Try this in your "else" block instead:
return this.userApplications.query({locale: locale}, $.proxy(function(data, locale){
this.localStorageService.add(Constants.key_applications+locale, JSON.stringify(data));
}, this));
In the following backbone scripts, I tried to change a collection in a view click event.
var StudentView = Backbone.View.extend({
initialize: function() {
console.log("create student items view");
this.collection.bind('add',this.render,this);
this.collection.bind('remove',this.render,this);
},
render : function(){
},
events :{
"click ":"select_students"
},
select_students: function(){
this.collection.reset([]);
_.each(students.models, function(m) {
if(m.get('name')=="Daniel"){
this.collection.add(m);
}
});
}
});
var students_view = new StudentView({el:$("#student_table"),collection:selected_students});
I got this error
How should I call "this.collection" in the code?
You should change you select_students to
select_students: function(){
var self = this;
this.collection.reset([]);
_.each(students.models, function(m) {
if(m.get('name')=="Daniel"){
self.collection.add(m);
}
});
}
The problem is that in JavaScript, the this context is lost in inner functions (like the one you pass to _.each) so the general pattern is to save a reference outside of that (self) and then use that in the inner function.
You can avoid using a reference at all, utilizing Backbone's collection filter method.
select_students: function () {
this.collection.reset(students.filter(function (student) {
return student.get('name') == 'Daniel';
});
}
Rather than using underscore's each() function, backbone collections can be iterated on directly, and can take a context to define what the 'this' variable refers to (passed as the second argument to each below).
So the best way to do this is to:
select_students: function(){
this.collection.reset([]);
students.each(function(m) {
if(m.get('name')=="Daniel"){
this.collection.add(m);
}
}, this);
}