Vue js data value is not changing after assign - vue.js

I have defined the data like this
data() {
return {
mdrender: '',
markdown: ''
};
},
And I have this function :
methods: {
interpretVars: function(markdown) {
$.getJSON("/api/v1/getdoc?code=" + this.$route.query.code, function (result) {
var interpreted = markdown.replace(/\{\#(companyName)\#\}/g, 'Demo')
.replace(/\{\#(docType)\#\}/g, result[0].datas.category).replace(/\{\#(version)\#\}/g, result[0].datas.version)
.replace(/\{\#(docTitle)\#\}/g, result[0].datas.title);
this.markdown = interpreted;
console.log(interpreted);
return interpreted;
});
}
},
Now the problem is that the markdown data value does not take the new value, while the variable that I'm console logging interpreted have the correct value.
I'm doing something wrong?
Thanks in advance for replying.

Your problem is the use of the function() statement. So you will loose the scope and this doesn't represents to the current Vue instance. There are two possible solutions to fix this:
Use an arrow function:
methods: {
interpretVars: function(markdown) {
$.getJSON("/api/v1/getdoc?code=" + this.$route.query.code, (result) => {
…
});
}
},
Use a helper variable:
methods: {
interpretVars: function(markdown) {
var $this = this;
$.getJSON("/api/v1/getdoc?code=" + this.$route.query.code, function (result) {
…
$this.markdown = interpreted;
});
}
},

I guess the best way of doing this would be doing it like this :
methods: {
async interpretVars(markdown) {
$.getJSON("/api/v1/getdoc?code=" + this.$route.query.code, function (result) {
var interpreted = markdown.replace(/\{\#(companyName)\#\}/g, 'Demo')
.replace(/\{\#(docType)\#\}/g, result[0].datas.category).replace(/\{\#(version)\#\}/g, result[0].datas.version)
.replace(/\{\#(docTitle)\#\}/g, result[0].datas.title);
this.markdown = interpreted;
console.log(interpreted);
return interpreted;
});
}
This should work as expected i guess, please don't assign this to temp variable.

Store this scope variable to a temporary variable and use that variable.
methods: {
interpretVars: function(markdown) {
let that = this;
$.getJSON("/api/v1/getdoc?code=" + this.$route.query.code, function (result) {
var interpreted = markdown.replace(/\{\#(companyName)\#\}/g, 'Demo')
.replace(/\{\#(docType)\#\}/g, result[0].datas.category).replace(/\{\#(version)\#\}/g, result[0].datas.version)
.replace(/\{\#(docTitle)\#\}/g, result[0].datas.title);
that.markdown = interpreted;
console.log(interpreted, that.markdown);
return interpreted;
});
}
},

Related

Vue.js | Filters is not return

I have a problem.
I am posting a category id with http post. status is returning a data that is true. I want to return with the value count variable from the back. But count does not go back. Return in function does not work. the value in the function does not return from the outside.
category-index -> View
<td>{{category.id | count}}</td>
Controller File
/**
* #Access(admin=true)
* #Route(methods="POST")
* #Request({"id": "integer"}, csrf=true)
*/
public function countAction($id){
return ['status' => 'yes'];
}
Vue File
filters: {
count: function(data){
var count = '';
this.$http.post('/admin/api/dpnblog/category/count' , {id:data} , function(success){
count = success.status;
}).catch(function(error){
console.log('error')
})
return count;
}
}
But not working :(
Thank you guys.
Note: Since you're using <td> it implies that you have a whole table of these; you might want to consider getting them all at once to reduce the amount of back-end calls.
Filters are meant for simple in-place string modifications like formatting etc.
Consider using a method to fetch this instead.
template
<td>{{ categoryCount }}</td>
script
data() {
return {
categoryCount: ''
}
},
created() {
this.categoryCount = this.fetchCategoryCount()
},
methods: {
async fetchCategoryCount() {
try {
const response = await this.$http.post('/admin/api/dpnblog/category/count', {id: this.category.id})
return response.status;
} catch(error) {
console.error('error')
}
}
}
view
<td>{{count}}</td>
vue
data() {
return {
count: '',
}
},
mounted() {
// or in any other Controller, and set your id this function
this.countFunc()
},
methods: {
countFunc: function(data) {
this.$http
.post('/admin/api/dpnblog/category/count', { id: data }, function(
success,
) {
// update view
this.count = success.status
})
.catch(function(error) {
console.log('error')
})
},
},

ExtJS Callback Functions Example

I'm a newbie at ExtJs and I'm struggling to figure out how to use callback functions in ExtJs. The ExtJs version I'm using is 4.2.1
Basically I want to chain the execution of 2 functions:
func1: function() {
}
func2: function() {
}
so that func2() only starts executing after func1() completes.
From what I've read so far, I need to use callback function, but for the life of me I cannot get it.
Here Is my code:
filter: function (filters, value) {
if (Ext.isString(filters)) {
filters = {
property: filters,
value: value
};
}
var me = this,
decoded = me.decodeFilters(filters),
i = 0,
length = decoded.length;
for (; i < length; i++) {
me.filters.replace(decoded[i]);
}
Ext.Array.each(me.filters.items, function (filter) {
Ext.Object.each(me.tree.nodeHash, function (key, node) {
if (filter.filterFn) {
if (!filter.filterFn(node)) node.remove();
} else {
if (node.data[filter.property] != filter.value) node.remove();
}
});
});
me.hasFilter = true;
console.log(me);
},
clearFilter: function() {
var me = this;
me.filters.clear();
me.hasFilter = false;
me.load();
},
isFiltered: function() {
return this.hasFilter;
},
filterNavAdminSTByUserName: function (nameValue) {
this.clearFilter();
this.filter([{
property: 'userName',
value: nameValue
}]);
}
My problem is that this.filter() gets executed before this.clearFilter(); How do I force this.filter() to execute only after this.clearFilter() completes?
Thanks in advance!
After some soul searching I've finally figured out how callback functions work.
So here is the solution:
clearAndFilter: function (nameValue) {
var me = this;
me.filters.clear();
me.hasFilter = false;
me.load({
scope: me,
callback: function () {
// filter the store
me.filter('userName', nameValue);
}
});
},
filterNavAdminSTByUserName: function (nameValue) {
this.clearAndFilter(nameValue);
}
Feels good to answer to my first ever post here!

Why could not load data from Adapter into JSONStore?

function getListPhoneNumbers() {
var data = {listContacts:[{name:'Ho Cong Vi',number:'12345666'},{name:'hcv',number:'6543218'}]};
WL.Logger.info('Data:'+JSON.stringify(data));
return data;
}
function addListPhoneNumber(data) {
WL.Logger.debug('Add Data to JSONStore: ' + data);
return;
}
function updateListPhoneNumber(data) {
WL.Logger.debug('Updata Data from JSONStore: ' + data);
return;
}
function deleteListPhoneNumber(data) {
WL.Logger.debug('Delete Data from JSONStore: ' + data);
return;
}
This is my code in main.js:
$('#show-all-btn').on('click', showAllData);
var collectionName = 'Contacts',
collections = {};
collections[collectionName] = {
searchFields: {
name: 'string',
number: 'string'
},
adapter: {
name: 'listPhoneNumbers',
add: 'addListPhoneNumber',
replace: 'updateListPhoneNumber',
remove: 'deleteListPhoneNumber',
load: {
procedure: 'getListPhoneNumbers',
param: [],
key: 'listContacts'
}
}
};
WL.JSONStore.init(collections)
function showAllData() {
$('#show-all-btn').on("click", function() {
$('#info').show();
});
WL.JSONStore.get(collectionName).load().then(function(res) {
alert('ok' + JSON.stringify(res));
}).fail(function(errorObject) {
alert(errorObject);
});
}
This is the error:
[wl.jsonstore] {"src":"load","err":18,"msg":"FAILED_TO_LOAD_INITIAL_DATA_FROM_ADAPTER_INVALID_L‌​OAD_OBJ","col":"Contact","usr":"jsonstore","doc":{},"res":{}
The error message is saying the load object you passed is invalid. This is probably because you passed param instead of params. Notice the s at the end.
Also, this code:
WL.JSONStore.init(collections)
function showAllData() {
$('#show-all-btn').on("click", function() {
$('#info').show();
});
WL.JSONStore.get(collectionName).load().then(function(res) {
alert('ok' + JSON.stringify(res));
}).fail(function(errorObject) {
alert(errorObject);
});
}
Looks wrong, maybe what you meant to write is something like this:
WL.JSONStore.init(collections).then(function () {
WL.JSONStore.get(collectionName).count().then(function (numberOfDocsInCollection) {
if(numberOfDocsInCollection < 1) {
WL.JSONStore.get(collectionName).load().then(function(res) {
//handle success
})
}
})
});
I omitted handling failures for brevity. Note that the load will will duplicate items in the collection if those items already exist, hence the count to check if the collection is empty or not.

Inheritance for durandal (HotTowel) viewmodels?

Simple question, pretty sure it's a complicated answer :)
Is it possible to implement some form of inheritance for viewmodels in Durandal?
So if you have a viewmodel something like this:
define(['durandal/app', 'services/datacontext', 'durandal/plugins/router', 'services/logger'],
function (app, datacontext, router, logger) {
var someVariable = ko.observable();
var isSaving = ko.observable(false);
var vm = {
activate: activate,
someVariable : someVariable,
refresh: refresh,
cancel: function () { router.navigateBack(); },
hasChanges: ko.computed(function () { return datacontext.hasChanges(); }),
canSave: ko.computed(function () { return datacontext.hasChanges() && !isSaving(); }),
goBack: function () { router.navigateBack(); },
save: function() {
isSaving(true);
return datacontext.saveChanges().fin(function () { isSaving(false); })
},
canDeactivate: function() {
if (datacontext.hasChanges()) {
var msg = 'Do you want to leave and cancel?';
return app.showMessage(msg, 'Navigate Away', ['Yes', 'No'])
.then(function(selectedOption) {
if (selectedOption === 'Yes') {
datacontext.cancelChanges();
}
return selectedOption;
});
}
return true;
}
};
return vm;
//#region Internal Methods
function activate(routeData) {
logger.log('View Activated for id {' + routeData.id + '}, null, 'View', true);
});
}
//#endregion
function refresh(id) {
return datacontext.getById(client, id);
}
});
Is it possible to make that into some kind of base type and inherit further viewmodels from it, being able to extend the requires list and so on?
There is another question on this, but the viewmodels don't appear to be quite the same as the one's that I build for durandal/HotTowel.
Thanks.
I'm pretty sure this can be accomplished with jQuery's extend method. This just occurred to me, so there may be something that I'm missing, but a basic example would be something along the lines of:
basevm.js
... your mentioned viewmodel
inheritingvm.js
define(['basevm'], function (basevm) {
var someNewObservable = ko.observable();
var vm = $.extend({
someNewObservable : someNewObservable
}, basevm);
return vm;
});
Please let me know if this works. I just coded from the top of my head and it hasn't been tested.
Just based off what your saying I came up with this. Let me know if this works for you and if it doesn't then let me know what I did wrong.
Thanks.
viewmodelBase
define(['durandal/app', 'services/datacontext', 'durandal/plugins/router', 'services/logger'],
function (app, datacontext, router, logger) {
var vm = function () {
var self = this;
this.someVariable = ko.observable();
this.isSaving = ko.observable(false);
this.hasChanges = ko.computed(function () { return datacontext.hasChanges(); });
this.canSave = ko.computed(function () { return datacontext.hasChanges() && !self.isSaving(); });
};
vm.prototype = {
activate: function (routeData) {
logger.log('View Activated for id {' + this.routeData.id + '}', null, 'View', true);
},
refresh: function (id) {
return datacontext.getById(client, id);
},
cancel: function () {
router.navigateBack();
},
goBack: function () { router.navigateBack(); },
save: function() {
var self = this;
this.isSaving(true);
return datacontext.saveChanges().fin(function () { self.isSaving(false); })
},
canDeactivate: function() {
if (datacontext.hasChanges()) {
var msg = 'Do you want to leave and cancel?';
return app.showMessage(msg, 'Navigate Away', ['Yes', 'No'])
.then(function(selectedOption) {
if (selectedOption === 'Yes') {
datacontext.cancelChanges();
}
return selectedOption;
});
}
return true;
}
};
return vm;
});
parent viewmodel
define([viewmodelBase], function (vmbase) {
var vm1 = new vmbase();
vm1.newProperty = "blah";
var vm2 = new vmbase();
});
I wrote a post on my blog that addresses this issue. In short, I use prototypical inheritance for all of my modal dialog views in one of my projects. Here's the link to the post I wrote (feel free to skip to the code part) and a jsFiddle example that demonstrates it.
Simplified example that can work in Durandal (NOTE: each view-model returns its constructor function, not an object):
viewmodels/modal.js
define(['durandal/system'],
function(system) {
var modal = function () {
this.name = 'Modal';
}
modal.prototype = {
activate: function() {
system.log(this.name + ' activating');
},
attached: function(view) {
system.log(this.name + ' attached');
},
deactivate: function() {
system.log(this.name + ' deactivating');
},
detached: function(view, parent) {
system.log(this.name + ' detached');
}
};
return modal;
});
viewmodels/child.js
define(['durandal/system', 'viewmodels/modal'],
function(system, Modal) {
var child = function() {
this.name = 'Child Modal';
}
// inherits from Modal
child.prototype = new Modal();
child.prototype.constructor = child;
child.prototype._super = Modal.prototype;
// overrides Modal's activate() method
child.prototype.activate = function() {
this._super.activate.call(this); // we can still call it from the _super property
system.log(this.name + ' activating [overridden version]');
};
return child;
});
I prefer this implementation because it supports code reuse, conforms to OOP principles as best as javascript allows, and it gives me the ability to call the base class' methods via the _super property when I need to. You can easily convert this as needed.

using contains instead of stringStartsWith knockout js

I have the folliwng on my model:
self.filteredItems = ko.computed(function () {
var filter = this.filter().toLowerCase();
if (!filter) {
return this.sites();
} else {
return ko.utils.arrayFilter(this.sites(), function (item) {
return ko.utils.stringStartsWith(item.Name().toLowerCase(), filter);
});
}
}, self);
I use it for a search on my page but rather than stringStartsWith I'd like some sort of .contains instead so I get results where my searchterm is contained anywhere in the string rather than just at the beginning.
I imagine this must be a pretty common request but couldnt find anything obvious.
Any suggestion?
You can use simply the string.indexOf method to check for "string contains":
self.filteredItems = ko.computed(function () {
var filter = this.filter().toLowerCase();
if (!filter) {
return this.sites();
} else {
return ko.utils.arrayFilter(this.sites(), function (item) {
return item.Name().toLowerCase().indexOf(filter) !== -1;
});
}
}, self);