How to pass extra variables and parameters to jQote2? - variables

I have a couple Javascript functions which concatenates a URL which I set to the variable c. I then try to pass that variable into jQote2:
$.get("emptyReq.tpl", function(tmpl,c) {
$("#reqs").jqoteapp(tmpl, result, c);
});
In emptyReq.tmpl, I'm doing the following:
<tr id="row">
<td name="id" class="id"><%= this.FormattedID %></td>
<td name="name" class="name"><%= this._refObjectName %></td>
<td name="state" class="state"><%= this.ScheduleState %></td>
<td name="owner" class="owner"></td>
</tr>
I've tried a couple of variations (this.c and c) and I've also tried different variables, but I'm not able to get the URL to display correctly.
c is labeled as undefined in the console, and the URL ends up being something like: http://127.0.0.1/xampp/py2/undefined instead of the actual c which is something like https://rally1.rallydev.com/slm/rally.sp#/2735190513d/detail/userstory/4599269614
Is there a way to pass the parameters properly? Or am I supposed to do the concatenation in the .tmpl file itself?
Here is what I've been using as a reference: jQote Reference.

rishimaharaj,
the jqoteapp method's third paramter is used to change the template tag (<% ... %> by default) on a per call basis. If you need to pass additional data to your template you have two options:
Make c a global variable (I wouldn't recommend that, though)
Copy c's value to the data parameter (recommended):
Please be aware that the copying needs to take into account of what type your
templating data is, i.e. a single object is handled different from an array of
objects!
$.get("emptyReq.tpl", function(tmpl,c) {
var data;
// 'result' seems to be a global var, thus making a copy is a good idea.
// Copying needs to take into account the type of 'result'
if ( Object.prototype.toString(result) === '[object Array]' ) {
data = result.slice(0);
} else {
data = [$.extend({}, result)];
}
// Now it is safe to add 'c' to the wrapping array. This way
// we won't override any homonymous property
data.c = c;
// Call the processing with our local copy
$("#reqs").jqoteapp(tmpl, data);
});
Once you've changed this, you will be able to access c through the templating
lamda's inherent property data:
<tr id="row">
... <a href="<%= data.c %>"><%= this.FormattedID ...
</tr>
Regards,
aefxx

Related

vue.js: How can I create a dynamic key in v-for when key is a date?

I am struggling to figure out how to create a :key value for my v-for loop & I believe that is why the order of my list(s) are random.
This is what my template looks like:
<div v-for="(items, index) in documents">
<h1>{{ index }}</h1> // 2020-06-02
...
<table class="table">
<tr>
<th>Name</th>
</tr>
<tr v-for="(item, index) in items" :key="index">
<td>{{ item.name }}</td> // Foo
</tr>
</table>
</div>
My documents prop looks like this:
{
2020-06-01: ['name': 'Foo', ...],
2020-06-02: ['name': 'Bar', ...],
2020-06-03: ['name': 'Baz', ...],
}
My props are returning the documents in the correct order, but they are not shown on screen in the correct order. For example, I'll see 2020-06-03, 2020-06-01, 2020-06-02 or a different combination. I think it's because I don't have a :key so Vue doesn't know how to order things.
Since I am using the index in my outter loops, I'm not sure how to get a unique key.
What I think I need is something like:
<div v-for="(items, date, index) in documents" :key="index">...</div>
But, that's not really how it works.
I've also tried something like:
<div v-for="(items, index) in documents" :key="`i-${index}`">...</div>
No luck there either.
Thank you for any suggestions!
EDIT
Thank you for your feedback! Here's a few notes.
I'm getting documents from another source. I'm passing it is as props to my component. Currently, I'm using a computed property to try to alter the actual object; maybe add a key or something. No luck just yet...
Just as you've stated, it is coming in as an object. Each key of the object is a date. Each date, then has an array that I'm also looping through.
Here is what documents looks like (also added a screenshot). You can see that the dates are in order. The props are straight from my external service, so things look great so far.
{
2020-06-01: ['name': 'Foo', ...],
2020-06-02: ['name': 'Bar', ...],
2020-06-03: ['name': 'Baz', ...],
}
[
you can go with index2 or whatever else you would like
I tried making index be date just to help keep things straight and yeah.. I tried adding a third argument in the v-for just in case there was an unknown secret I could tap into (sadly no) :)
the format of your prop is messing me up mostly.
Same here, I'm just not able to understand why the order looks good in my props, but when looping through things, its pretty random.
show what you want the table to look like
This is the result I'm trying to accomplish.
<h2>2020-06-01</h2>. // this is the "missing" index (outer loop)
<table>
<tr>
<th>Name</th>
<th>Email</th>
</tr>
<tr> // this is the array that exists within each date
<td>Foo</td>
<td>foo#example.com</td>
</tr>
</table>
Edit/Solution
Thank you so much #Goofballtech! Your answer really helped me think about what I had and directions to try. Here's what I ended up with. sortedDocuments is a computed property; this.documents is a reference to the documents props that is getting passed in.
sortedDocuments() {
const data = this.documents;
return Object.keys(data)
.map((date) => {
return {
date: date,
data: data[date],
}
})
.sort(function (a, b) {
let dateA = new Date(a.date);
let dateB = new Date(b.date);
return dateA - dateB;
})
.reverse();
},
:key is used to watch for changes, not necessarily for order.
2 things.
if you want to maintain a specific order the general solution is to use an array. Order of object (although there is a bit of method to the madness) cannot necessarily be counted upon.
I believe you should used a computed property to modify these as you require then iterate over that array instead of using the object directly for what it seems you are trying to do. Will be back will an edit adding code in a moment.
Edit1 -
General information about indexes in v-for. The word index is not some magic keyword. If you have nested v-for you can do this:
<div v-for="(stuff, index) in stuffing">
display stuff here, index is your key
<div v-for="otherStuff, skdjdfhfyjsksj) in theOtherThings">
skdjdfhfyjsksj is your key value here
</div>
</div>
index is shown in examples to be clear but you can go with index2 or whatever else you would like there. It's getting passed as the second argument and that's where the magic happens.
Back to the base issue...So the format of your prop is messing me up mostly. Sorting the existing entries is straight forward but there really isn't a key:value array in javascript. Those are objects. So where are you getting the documents prop from originally? Is that something you are creating to pass down or is it coming that way from an external source?
sorting of the dates can be done like this in computed, this doesn't include the rest of the data yet as I'm not sure if you need to convert those on the fly or if we can change the prop before it gets here. I changed your document arrays to objects because the code would never show anything with that data formatted as an array as it complained about a missing ] since it did not expect the array key:value formatting.
https://jsfiddle.net/goofballtech/hmr6uw2a/65/
computed: {
sortedDates(){
return Object.keys(this.documents)
.sort((a,b) => a > b ? 1 : 0)
}
},
Final request for this edit, can you show what you want the table to look like? Having that context would help in finding the optimal data structure to achieve the results you need.
Edit2 -
Assuming the object can be an array of objects, and there is potential to have more than one name/email per date array. The below would work.
It all hinges on those funky arrays though.
Might be easier for you to copy the raw return from the API and just go in in to sterilize the data so i can see how the arrays are formatted.
https://jsfiddle.net/goofballtech/hmr6uw2a/141/
<div v-for="(docDate, index) in sortedDates" :key="index">
<h3>
{{docDate.date}}
</h3>
<table class="table">
<tr>
<th>Name</th>
<th>Email</th>
</tr>
<tr v-for="(item, index2) in docDate.data.length" :key="index2">
<td>{{documents[docDate.date][index2].name}}</td>
<td>{{documents[docDate.date][index2].email}}</td>
</tr>
</table>
</div>

Syntax for data binding with Index

Stuck on what is most likely just a syntax issue. I want to replace the '1' in 'play1' with the v-for index.
<tr v-for="index in 5">
<td>{{player1.round1.play1}}</td>
<td>{{player2.round1.play1}}</td>
</tr>
I tried many variations of {{player1.round1.play + index}} with no success.
<tr v-for="index in 5">
<td>{{player1.round1['play'+index]}}</td>
<td>{{player2.round1['play'+index]}}</td>
</tr>
within the double-curlies of the vue template, the content is handled as javascript.
when looking up an object in javascript you can either pass the key using the dot notation or the bracket syntax.
For example, if you have an object such as this:
const objectA = {
objectB: {
objectC: {
}
}
};
you can look up objectC either using dot notation:
objectA.objectB.objectC
or using brackets:
objectA['objectB']['objectC']
note that when you are using brackets, that you have to use a simple type, a number or a string (technically symbols are also accepted, but let's not worry about that right now). The bracket syntax does however allow you to use a variable in order to access an object, like so:
let b='objectB';
let c='C';
objectA[b]['object' + c];
objectA[b][`object${c}`];
knowing this, you can then use that to access the right object inside your vue template like this:
<td>{{player1.round1['play'+index]}}</td>
or, using template literals:
<td>{{player2.round1[`play${index}`]}}</td>

vue idb format variable

Hello I'm making a web app using vuex and vue idb.
In one of my view I have a table with filter fields.
My data are stored using vue-idb and filter fields call applyFilter methods function using the input text box event and the header name of the column's cell
Here is my html
...some html
<!--columns filters-->
<tr>
<td v-if='shownHeaders.length > 0'>
<input type='checkbox' #change='updateCheckboxList(-1)' :checked='checkAllCheckbox'>
</td>
<td v-for='(header,index) in headers' v-if='headers.indexOf(header)>-1'>
<input #keyup="applyFilter(header,$event )" :disabled="thinking" :placeholder='header +" filter"'>
</td>
</tr>
Here is my component
some code ...
applyFilter (header, e) {
// apply filter after enter key has been pressed
if (e.keyCode === 13) {
console.log('Filtering column ' + header + ' with ' + e.target.value)
// not working unsing dynamical variable, but it does while using static variable like uid
store.dispatch('tasksSetFilter', {header: e.target.value}) // this doesn't works
// store.dispatch('tasksSetFilter', {id: e.target.value}) // this works
My issue is that I'm unable to use header variable (a string) as key of dict passed with tasksSetFilter, but if I replace it by a variable having the same name it works.
Is there a way to transform string to variable name to solve my problem?
Try this:
store.dispatch('tasksSetFilter', {[header]: e.target.value})
What this syntax does is set the parameter to an object where the key will be whatever the value of header is. This is a newer syntax that came about with ES2015.
If you could not support ES2015, you could build the parameter this way:
let filter = {}
filter[header] = e.target.value
store.dispatch('tasksSetFilter', filter)

Aurelia ui-virtualization infinite-scroll-next function not being hit after data refresh

I'm using aurelia's ui-virtualization library to create a table using virtual-repeat and infinite-scroll-next. Html looks something like this:
<table>
<thead>
...
</thead>
<tbody>
<tr virtual-repeat.for="item of items" infinite-scroll-next="getMore">
...
</tr>
</tbody>
</table>
This works great, except I have certain ui components and interactions that update what is in my list array. Once that has be updated, the infinite-scroll-next function (getMore()) is never called. I update something like this:
update() {
let vm = this;
vm.apiService.getData(vm.filterOption)
.then(response => {
vm.items = response.content.items;
});
}
Where filterOptions are changed through the ui and apiService.getData() returns a promise from an http call. The data in the table updates correctly, but the infinite scroll is then broken.
Am I doing something wrong, or is this a bug in ui-virtualization?
Edit:
It appears there are some properties added to the array __array_observer__ and __observers__. Thinking overwriting the whole array and thus removing these properties might be causing the problem, I tried an approach where I just add or remove elements appropriately. This does not work either.
Edit:
It seems to fail if I leave fewer than 7 of the original elements in the array.

Detecting Selected Row in html table Knockout/ASP.NET MVC

I've loaded an ASP.NET MVC viewModel into KnockoutJS using ko.mapping.fromJS(Model).
My viewModel looks something like this:
public IEnumerable<FunkyThing>funkyThings;
public FunkyThing selectedFunkyThing;
I've then got in my HTML View a table which looks something like this
<tbody data-bind="foreach: funkyThings">
<tr>
<td data-bind="text:name"></td>
<td data-bind="text:funkiness"></td>
<td>
</td>
</tr>
</tbody>
and all is good with this table. Clicking the select funky thing link happily calls the selectFunkyThing function:
model.selectFunkyThing= function (funkyThing) {
window.location = '#Url.Action(MVC.FunkyThingController.Index())' + "?funkyThingID=" + funkyThing.funkyThingID();
};
which in turn refreshes the page. The MVC viewmodels is reloaded and selectedFunkyThing is populated with the selected FunkyThing and the knockout view models are then re-read from the MVC viewmodel. So far so good.
I then wanted to update the table to highlight the selected entry.
So I updated the tr line as follows:
<tr data-bind="css:{'selected': $root.isSelected()}">
and created the new knockout function:
model.isSelected = function (funkyThing) {
return funkyThing.funkyThingID== model.selectedFunkyThing.funkyThingID;
};
but... it's not working.
Chrome throws a javascript exception stating that the FunkyThing parameter is undefined.
Technically I figure I could solve it by changing the MVC viewModel to actually set a isSelected on each FunkyThing within the array. However I figure there's got to be away of doing this from Knockout?
You were close! I added the ko.utils.unwrapObservable call because I bet the funkyThingID is an observable and not just a straight property - you did this yourself in your selectFunkyThing function. You could just execute them as well. I like the verbosity of unwrap though.
model.isSelected = function (funkyThing) {
var thisId = ko.utils.unwrapObservable(model.selectedFunkyThing.funkyThingID);
return ko.utils.unwrapObservable(funkyThing.funkyThingID) == thisId;
};
and then in your document you actually have to execute this function when ko parses the binding
<tr data-bind="css:{'selected': $root.isSelected($data)}">
Are those properties not both observables, so you need to reference them as functions? You also need to make your function a computed observable, I think:
model.isSelected = ko.computed(function (funkyThing) {
return funkyThing().funkyThingID() == model.selectedFunkyThing().funkyThingID();
});