I have this Axios patch but I only want to include the last three, if the hyperlink_column isn't null. How can I do this?
Thanks,
Mick
axios.patch('/' + self.table + '/' + self.rowId,{
name: self.name,
SQL:self.SQL,
area_id:self.area_id,
report_type_id:self.report_type_id,
mode:self.mode,
database_connection_id:self.database_connection_id,
pagination: self.pagination,
show_export_buttons : self.show_export_buttons,
filters : self.filters,
description : self.description,
category_id : self.category_id,
hyperlink_column : self.hyperlink_column,
linked_report : self.linked_report,
link_parameter : self.link_parameter,
Since by the look of it, it looks like the second parameter is an object, so one way of doing it, would be to invoke a function as the second parameter and passing your data inside self as an argument. The function will then check if self.hyperlink_column exists and then return an object accordingly. like this
Repl
PS : This is done using closure.
Related
Noob here. I am trying to build a dropdown for only the div id matches my specific name.
For example, my table column names are : A, B, C.
I only want to enable dropdown for column A
My table is a template that looks like follows:
template(v-for="field in tableFields")
th(:id="'_' + field.name")
select(v-if="field.name ==='A'" v-model="selectedScope"
option
option(v-for="scope in scopes" v-bind:value="scope" ) {{scope}}
This works but i want to extract the v-if="field.name ==='A'" to a function.
I have the following but it didn't work:
template(v-for="field in tableFields")
th(:id="'_' + field.name")
select(v-if="shouldProvideSelectOption(field)" v-model="selectedScope"
option
option(v-for="scope in scopes" v-bind:value="scope" ) {{scope}}
And under computed, i have something like this:
computed: {
shouldProvideSelectOption: function (field) {
return field.name === 'A'
}
},
Why?
use a method instead of computed property :
methods : {
shouldProvideSelectOption: function (field) {
return field.name === 'A'
}
}
Edit
Like #RoyJ said in the comment below :
computeds do not take arguments (except for setters). A computed is used like a variable
I'm trying to determine the best pattern to solve the following:
I want to show a list of people in a specific department
I made the department index a regular, reactive Vue property
I made the list of people in the department a computed property
Now:
My backend (a Mac app) can dispatch a "Person at index changed" event and I must reload the name of a single person.
But: the person property is an item in a computed property (i.e. "people", see code below).
How can I update the name of a person in the list list of people, which in turn is a computed property (although it is "computed" from the departmentIndex + backend call)?
I assume that I have a mistake in my original setup. Maybe the people list should not be a computed property in the first place?
Here is the code:
function pretendUpdateEventFromBackend() {
var event = new CustomEvent('PersonUpdated', {detail:{index:1, name:'Jimmy'}});
document.dispatchEvent(event);
}
var backend = {
// The actual backend is a Mac app with an embedded WebView...
listPeopleInDepartment(departmentIndex) {
return [
{name:'John'},
{name:'James'},
{name:'Jane'}
];
}
}
var app = new Vue({
el: '#app',
data: {
message:'',
departmentIndex:0,
},
computed: {
people() {
return backend.listPeopleInDepartment(this.departmentIndex);
}
},
created() {
const me = this;
document.addEventListener('PersonUpdated', function(e){
me.message += 'Updated ';
var personIndex = e.detail.index;
var newName = e.detail.name;
// How can I update person in the list of computed people here?
// Or how can I force a reload of the people list?
me.message += 'Person at: ' + personIndex + ' new name: ' + newName + "\n";
});
},
});
Html:
<button onclick="pretendUpdateEventFromBackend()">Trigger Update Event from Backend</button>
<div id="app">
<div class="person" v-for="person in people">
Name: {{ person.name }}
</div>
<pre>{{message}}</pre>
</div>
EDIT:
Try it on jsbin: http://jsbin.com/guwezoyena/1/edit?html,js,output
I just thought I should give you some further insight on your setup:
If listPeopleInDepartment is an ajax call in your actual code, this might be a bad pattern. See, Vue will identify every property (including other computed properties) that is used within a computed property and make it sure to re-compute it whenever any of them changes. In your case, this would mean whenever departmentIndex changes it'll recompute people.
Here's why it might be problematic, since you must return the result of the ajax request, it can't be asynchronous so it'll be a blocking call that would render the page unresponsive while it runs. Also, let's say you were viewing department 1, then you change to 2, if you go back to 1 it'll have to reload the people in department 1 because it's not stored anywhere.
You should probably implement some caching strategy and have ajax loads only when that data isn't already available, also in a non blocking fashion. You could achieve this with an array that stores the arrays of peopleInDepartment indexed by department id, and a watcher for departmentIndex that would do something like this:
function (newValue){
if (!this.peopleCache[newValue]){
var that = this;
//Load it via ajax
loadPeopleInDepartment(newValue, function(result){
that.peopleCache[newValue] = result;
});
}
}
My aim is to replace the teacher-id(f_teacher) of one outputted array with the teacher name of another array. I wrote a custom filter, that should do the job:
angular.module('core')
.filter('replaceId', function () { //filter, which replaces Id's of one array, with corresponding content of another array
return function (t_D, s_D, t_prop, s_prop) { //data of target, data of source, target property, source property
var replacment = {};
var output = [];
angular.forEach(s_D, function (item) {
replacment[item.id] = item[s_prop]; //replacment - object is filled with 'id' as key and corresponding value
});
angular.forEach(t_D, function (item) {
item[t_prop] = replacment[item[t_prop]]; //ids of target data are replaced with matching value
output.push(item);
});
return output;
}
});
I use a 'ng-repeat' like this:
<tr ng-repeat="class in $ctrl.classes | filter:$ctrl.search | replaceId:$ctrl.teachers:'f_teacher':'prename' | orderBy:sortType:sortReverse">
<td>{{class.level}}</td>
<td>{{class.classNR}}</td>
<td>{{class.f_teacher}}</td>
</tr>
But it only outputs an empty column. Now the strange thing: If I follow the steps with the debugger, it works for the first time the filter is performed. But when it is performed a second time it outputs an empty column.
I noticed that the returned object of the filter overwrites the $ctrl.classes - array, but normally this shouldn't be the case?
Here is a plnkr:
https://plnkr.co/edit/EiW59gbcLI5XmHCS6dIs?p=preview
Why is this happening?
Thank you for your time :)
The first time through your filter the code takes the f_teacher id and replaces it with the teacher name. The second time through it tries to do the same thing except now instead of getting a teachers ID in f_teacher it finds the teacher's name so it doesn't work. You could fix it by making a copy of the classes instead of modifying them directly. e.g.
angular.forEach(t_D, function (item) {
var itemCopy = angular.copy(item);
itemCopy[t_prop] = replacment[itemCopy[t_prop]];
output.push(itemCopy);
});
https://plnkr.co/edit/RDvBGITSAis3da6sWnyi?p=preview
EDIT
Original solution will trigger an infinite digest because the filter returns new instances of objects every time it runs which will cause angular to think something has changed and retrigger a digest. Could you just have a getter function that gets a teachers name instead of using a filter?
$scope.getTeacherName = function(id) {
var matchingTeachers = $scope.teachers.filter(function(teacher) {
return teacher.id == id;
})
//Should always be exactly 1 match.
return matchingTeachers[0].prename;
};
And then in the HTML you could use it like
<tr ng-repeat="class in classes">
<td>{{class.level}}</td>
<td>{{class.classNR}}</td>
<td>{{getTeacherName(class.f_teacher)}}</td>
</tr>
https://plnkr.co/edit/gtu03gQHlRIMsh9vxr1c?p=preview
I would like to bind a property (flag_baz in this case) from a JSONModel to a checkbox.
Thing is that the json model looks like this.
{
foo: "Foo",
bar:"Bar",
flag_baz : "X"
}
in this case X means "true" and an empty string means "false"
What i would like to do is evaluate a function for binding from model to the checkbox (that would translate "X"/"" to true/false) and evaluate some other function when binding from the checkbox to the model (that would translate from true/false back to "X"/"").
i would like to have something like this:
var checkBox = new Checkbox();
checkBox.bindProperty("checked", "flag_baz", funcFromStringToBool, funcFromBoolToString);
i know the funcFromStringToBool is called a formatter.
how would i add the funcFromBoolToString function?
Hope this makes sense.
Thx in advance.
Well in case some cares i've found the answer on my own.
All bindings can use a type like so
checkBox.bindProperty("checked", {
path : "flag_baz",
type : new BooleanStringType()
});
the BooleanStringType class would look like this:
sap.ui.model.SimpleType.extend("BooleanStringType", {
//called when going from model to ui
formatValue : function(flag_baz){
return flag_baz === "X";
},
//called when going from ui back to the model
parseValue : function(flag_baz){
return flag_baz ? "X" : "";
},
validateValue : function(flag_baz){
//some validation if needed
}
});
I need to get the total of the following example:
$scope.fees = {
basic: 1,
premium: 2,
total: this.basic + this.premium
}
Why won't this work? It says this is undefined. Is there a way to achieve this without having to write out total: $scope.fees.basic + $scope.fees.premium.
I'd love if there was a way to shorten it.
EDIT: I'd actually have to add the total property outside of $scope.fees. $scope.fees.total = ...
You can use function ..
Hello {{ total() }}
function FeeController($scope) {
$scope.fees = {
basic: 1,
premium: 2,
};
$scope.total = function() {
return $scope.fees.basic + $scope.fees.premium;
};
}
Why this.basic doesn't work
this is evaluated in the context of the function that contains this statement. So this doesn't refer to the $scope.fees object, but to the controller.
Why total : $scope.fees.basic + $scope.fees.premium doesn't work either
At the moment that the expression $scope.fees.basic + $scope.fees.premium is evaluated the $scope.fees object doesn't exist yet, because you're in the middle of creating it. Therefore it will result in an error like "Cannot read property basic of undefined".
How to solve this
There isn't any solution other than what you've already found that results in the behaviour you want, so unfortunately you'll have to stick with it.
You might consider using the "controller as class" pattern which lessens your dependency on the $scope. You could do something like this:
app.controller('FeeCtrl', function () {
this.basic =1;
this.premium =2;
this.total = this.basic + this.premium;
});
Then you can inject this controller right into your dom:
<div ng-controller="FeeCtrl as fee">
{{ fee.total }}
</div>
There are more detailed instructions here
http://toddmotto.com/digging-into-angulars-controller-as-syntax/