I am storing some settings in the database with keys and JSON data but when I get these settings from a Laravel API, it returns an array which becomes a hectic work in reassigning data to the input fields. I want to know if there is an easier way of doing it.
So far I have tried iterating and using the switch statement to identify keys and reassign them. But the problem is I can't access the VueJS data variable in the loop.
Here is a look at the database table:
Database Table
Here are the objects I am using in Vue:
helpful_notification: {
email: false,
sms: false,
push: false,
},
updates_newsletter: {
email: false,
sms: false,
push: false,
},
Here is my Code to Iterate over results:
axios.get('/api/notificationsettings')
.then(response => {
var data = response.data;
let list = [];
console.log(data)
$.each(data, function(i, j){
switch(j.key){
case 'transactional':
var settings = JSON.parse(j.settings)
var x = {
transactional : settings
}
list.push(x)
break;
case 'task_reminder':
var settings = JSON.parse(j.settings)
x = {
task_reminder : settings
}
list.push(x)
break;
}
});
this.transactional = list;
// this.task_reminder= list.task_reminder;
console.log(list);
})
.catch(error => {
});
In JavaScript, functions have their own scope, save for a few exceptions. Which means that, inside your anonymous function (i.e:
$.each(data, function(i, j){
// this here is the function scope, not the outside scope
})
...), this is not the outside scope, it's the function's scope
There are two ways to make the outside scope available inside your function:
a) place it inside a variable
const _this = this;
$.each(data, function(i, j){
// this is function scope,
// _this is outside scope (i.e: _this.list.task_reminder)
})
b) use an arrow function
$.each(data, (i, j) => {
// this is the outside scope
// the arrow function doesn't have a scope.
})
The above is a simplification aimed at helping you access the outside scope inside your function. But this can differ based on the context it is used in. You can read more about this here.
Related
Following the advice given on one of my other questions (Get a list of all objects from loaded model), I added this code on my application to retrieve all properties from all objects:
function onGeometryLoadedEvent(viewer) {
var dbIds = Object.keys(
viewer.model.getData().instanceTree.nodeAccess.dbIdToIndex
);
this.viewer.model.getBulkProperties(
dbIds,
{
propFilter: false,
ignoreHidden: true
},
(objects) => console.log(objects),
() => console.log('error')
)
}
It correctly shows all the objects. The problem is it takes A LOT of time to complete (+1 minute), even for a model with just 10,000 objects.
Is this normal?
I really need the list of objects with their categories, I have to sort them after getting them to present a list of all the available categories and properties to the user.
I know I can use the Model Derivatives API, but I'd like to avoid it if possible.
Note that when you list all elements on the model it will include those that are not visible, like categories. If you need only elements on the model, then you need the leaf of the model. This article described it and the source code is below:
function getAllLeafComponents(viewer, callback) {
var cbCount = 0; // count pending callbacks
var components = []; // store the results
var tree; // the instance tree
function getLeafComponentsRec(parent) {
cbCount++;
if (tree.getChildCount(parent) != 0) {
tree.enumNodeChildren(parent, function (children) {
getLeafComponentsRec(children);
}, false);
} else {
components.push(parent);
}
if (--cbCount == 0) callback(components);
}
viewer.getObjectTree(function (objectTree) {
tree = objectTree;
var allLeafComponents = getLeafComponentsRec(tree.getRootId());
});
}
Now with the .getBulkProperties you can specify which property you want, so something like Category, right? So specify that, as shown at this article and used with the above .getAllLeafComponent function:
getAllLeafComponents(viewer, function (dbIds) {
viewer.model.getBulkProperties(dbIds, ['Category'],
function(elements){
// ToDo here
// this will only include leaf with Category property
})
})
And I would expect this to be faster than your original code, as I'm filtering elements and properties.
I have a function in node.js that looks like this:
exports.getAllFlights = function(getRequest) {
// this is the package from npm called "async"
async.map(clients, getFlight, function(err, results) {
getRequest(results);
});
}
The variable clients should be a JSON that looks like this:
{'"A4Q"': 'JZA8187', "'B7P"': 'DAL2098' }.
I expect that the map function will pass the individual indices of the array of the variable clients to getFlight. However, instead it passed the values of that each(ex: 'DAL2098', 'JZA8187' and so on).
Is this the expected functionality? Is there a function in async that will do what I want?
The signature of getFlight is getFlight(identifier, callback). Identifier is what is currently messed up. It returns callback(null, rtn). Null reprsents the nonexistence of an error, rtn represents the JSON that my function produces.
Yes, that's the expected result. The documentation is not very clear but all iterating functions of async.js pass the values of the iterable, not the keys. There is the eachOf series of functions that pass both key and value. For example:
async.eachOf(clients, function (value, key, callback) {
// process each client here
});
Unfortunately there is no mapOf.
If you don't mind not doing things in parallel you can use eachOfSeries:
var results = [];
async.eachOfSeries(clients, function (value, key, callback) {
// do what getFlight needs to do and append to results array
}, function(err) {
getRequest(results);
});
Another (IMHO better) workaround is to use proper arrays:
var clients = [{'A4Q': 'JZA8187'},{'B7P': 'DAL2098'}];
Then use your original logic. However, I'd prefer to use a structure like the following:
var clients = [
{key: 'A4Q', val: 'JZA8187'},
{key: 'B7P', val: 'DAL2098'}
];
First create a custom event. Attach a listener for return data. then process it.
var EventEmitter = require('events');
var myEmitter = new EventEmitter();
myEmitter.emit('clients_data',{'"A4Q"': 'JZA8187'}); //emit your event where ever
myEmitter.on('clients_data', (obj) => {
if (typeof obj !=='undefined') {
if (obj.contructor === Object && Object.keys(obj).lenth == 0) {
console.log('empty');
} else {
for(var key in obj) {
var value = obj[key];
//do what you want here
}
}
}
});
Well, you need to format your clients object properly before you can use it with async.map(). Lodash _.map() can help you:
var client_list = _.map(clients, function(value, key) {
var item = {};
item[key] = value;
return item;
});
After that, you will have an array like:
[ { A4Q: 'JZA8187' }, { B7P: 'DAL2098' } ]
Then, you can use async.map():
exports.getAllFlights = function(getRequest) {
async.map(client_list, getFlight, function(err, results) {
getRequest(results);
});
};
I have 5 tabs with the same user's data. Each tab has an input to search by term. How can reuse code for fetching users and searching them in opened tab. Code is in this JSFiddle:
var listing = Vue.extend({
data: function () {
return {
query: '',
list: [],
user: '',
}
},
computed: {
computedList: function () {
var vm = this;
return this.list.filter(function (item) {
return item.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1
})
}
},
created: function () {
this.loadItems();
},
methods: {
loadItems: function () {
this.list = ['mike','bill','tony'],
},
}
});
var list1 = new listing({
template: '#users-template'
});
var list2 = new listing({
template: '#users-template2'
});
Vue.component('list1', list1);
Vue.component('list2', list2)
var app = new Vue({
el: ".lists-wrappers",
});
query - string of term to search
ComputedList - array of filtered data by search term.
But getting error for "query" and "ComputedList".
[Vue warn]: Property or method "query" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option. (found in root instance).
You were really close with what you had. The reason for the query error is you were using query in what looked like, to Vue, the root instances scope. You shouldn't put templates inside of other templates. Always have them outside of it (preferably as a string in your component definition).
You can read about that a bit here: https://vuejs.org/guide/components.html#DOM-Template-Parsing-Caveats
Here's how I'd approach your situation: https://jsfiddle.net/crswll/apokjqxx/6/
i have problem rendering my view...the view return always the last in the json object: This is the code:
Router.js:
var list = new clientCollection();
var cards = new cardsView({model:list})
list.fetch({success: function (collection, response, options) {
cards.render();
}
});
Cards.js view:
....
tagName: 'section',
className: 'list',
template: Handlebars.compile(cardsTemplate),
render: function () {
var list = this.model.toJSON(),
self = this,
wrapperHtml = $("#board"),
fragment = document.createDocumentFragment();
$(list).each(function (index, item) {
$(self.el).html(self.template({card: item}));
$.each(item.cards, function (i, c) {
var card = new cardView({model : c});
$(self.el).find('.list-cards').append(card.render().el);
});
fragment.appendChild(self.el);
});
wrapperHtml.append(fragment.cloneNode(true));
},
...
This is my json data:
[
{"id":"9","name_client":"XXXXXXX","cards":[]},
{"id":"8","name_client":"XXXXXXX","cards":[{"id":"8","title":"xxxxx.it","description":"some desc","due_date":"2016-01-23","sort":"0"}]}
]
Can u help me to render the view?
It's hard to know for sure without seeing how the view(s) are attached to the DOM, but your problem appears to be this line ...
$(self.el).html(self.template({card: item}));
That is essentially rendering each element in the collection as the full contents of this view, then replacing it on each iteration. Try instead appending the contents of each template to the view's element.
Also, since you tagged this with backbone.js and collections, note that the easier, more Backbone-y way to iterate through a collection would be:
this.model.each(function(item) {
// 'item' is now an instance of the Backbone.Model type
// contained within the collection. Also, note the use
// of 'this' within the iterator function, as well as
// this.$el within a View is automatically the same as
// $(self.el)
this.$el.append(this.template({ card: item });
// ... and so on ...
// By providing 'this' as the second argument to 'each(...)',
// the context of the iterator function is set for you.
}, this);
There's a lot packed in there, so ...
Backbone.Collection Underscore Methods
Backbone.View this.$el
Let's say I have a site which saves phone numbers via an HTTP call to a service and the service returns the new id of the telephone number entry for binding to the telephone number on the page.
The telephones, in this case, are stored in an array called 'telephones' and datacontext.telephones.updateData sends the telephone to the server inside a $.Deferred([service call logic]).promise();
uploadTelephones = function (deffered) {
for (var i = 0; i < telephones.length; i++){
deffered.push(datacontext.telephones.updateData(telephones[i], {
success: function (response) {
telephones[i].telephoneId = response;
},
error: function () {
logger.error('Stuff errored');
}
}));
}
}
Now if I call:
function(){
var deferreds = [];
uploadTelephones(deferreds);
$.when.apply($, deferreds)
.then(function () {
editing(false);
complete();
},
function () {
complete();
});
}
A weird thing happens. All the telephones are sent back to the service and are saved. When the 'success' callback in uploadTelephones method is called with the new id as 'response', no matter which telephone the query relates to, the value of i is always telephones.length+1 and the line
telephones[i].telephoneId = response;
throws an error because telephones[i] does not exist.
Can anyone tell me how to keep the individual values of i in the success callback?
All of your closures (your anonymous functions capturing a variable in the local scope) refer to the same index variable, which will have the value of telephones.length after loop execution. What you need is to create a different variable for every pass through the for loop saving the value of i at the instance of creation at for later use.
To create a new different variable, the easiest way is to create an anonymous function with the code that is to capture the value at that particular place in the loop and immediately execute it.
either this:
for (var i = 0; i < telephones.length; i++)
{
(function () {
var saved = i;
deffered.push(datacontext.telephones.updateData(telephones[saved],
{
success: function (response)
{
telephones[saved].telephoneId = response;
},
error: function ()
{
logger.error('Stuff errored ');
}
}));
})();
}
or this:
for (var i = 0; i < telephones.length; i++)
{
(function (saved) {
deffered.push(datacontext.telephones.updateData(telephones[saved],
{
success: function (response)
{
telephones[saved].telephoneId = response;
},
error: function ()
{
logger.error('Stuff errored ');
}
}));
})(i);
}
should work.
Now, that's a bit ugly, though. Since you are already going through the process of executing an anonymous function over and over, if you want your code to be a little bit cleaner, you might want to look at Array.forEach and just use whatever arguments are passed in, or just use jQuery.each as you are already using jQuery.