Postman visualization: Can I create conditional statements? - postman

I am returning a JSON body from an API using postman. I am using the visualization feature of Postman to create a template to organize and loop through the data. https://learning.postman.com/docs/sending-requests/visualizer/
Question: Can I create conditional statements? Test for the value of certain elements? The handlebars features do not seem to work.
Example:
{{#each response}} {{#if name = 'abc'}}
<td>ABC</td>
{{else}}
<td>{{name}}</td>
{{/if}} {{/each}}
Thanks!

You can use if blocks but not quite like that, as the syntax is slightly different. You can find more information about how these work here:
https://handlebarsjs.com/guide/builtin-helpers.html
You can use the if helper to conditionally render a block. If its argument returns false, undefined, null, "", 0, or [], Handlebars will not render the block

Just adding to Dannys answer:
https://github.com/postmanlabs/postman-app-support/issues/7373#issuecomment-601402891
As of now custom helpers are not supported so you have to do the if logic inside your script:
Example:
https://www.getpostman.com/collections/d3a91ce456800d061156
you can import this collection by clicking import link in postman
Explanation:
set get url as:
https://reqres.in/api/users?page=2
test script as :
template = `<table bgcolor="#FFFFFF">
<tr>
<th>Name</th>
<th>Email</th>
</tr>
{{#each response}}
{{#if George}}
<tr>
<td>Found george</td>
<td>{{email}}</td>
</tr>
{{/if}}
{{/each}}
</table>
`;
data =pm.response.json().data
data.map((a)=> a[a.first_name]=true)
// Set visualizer
pm.visualizer.set(template, {
// Pass the response body parsed as JSON as `data`
response: data
});
If you read the handle bar documentation :
https://handlebarsjs.com/guide/builtin-helpers.html
You can use the if helper to conditionally render a block. If its
argument returns false, undefined, null, "", 0, or [], Handlebars will
not render the block.
so here we are hacking this behavior , i am creating a key in the data object with same name as the value i am checking for
if the value doesn't exists then the element will be undefined else it will pass.

Related

Ember - actions within link-to blocks

I am building a component in Ember.js which includes a table. Each tr in that table is created using {{#link-to ...}} so that clicking anywhere on the row will take a user to another route.
However, I'd like to make a td element in those rows clickable to open a link in a new window. I'm doing this as an action.
Right now, clicking the proper td element will both trigger the {{#link-to}} redirect and activate the action on the td element as well.
Instead, I'd like a click on the proper td element to only trigger that element's action, and ignore the {{#link-to}} event above. How would I go about doing this?
This is what my code looks like:
<table>
{{#link-to 'widget' widget.id tagName='tr'}}
<td>Go to link-to</td>
<td {{action 'sendMail' widget.email}}>Send Email</td>
{{/link-to}}
</table>
Look at this twiddle implemented your case.
You need to call event.stopPropagation for that you need to have event object, to get it I used onclick={{action
<table>
{{#link-to 'my-route' tagName='tr' bubble=false}}
<td>Go to link-to</td>
<td onclick={{action 'sendMail' }}>Send Email</td>
{{/link-to}}
</table>
In sendMail, you need to stop event propagation.
actions:{
sendMail(event){
console.log('sendMail');
event.stopPropagation();
}
}

How to store EmberJS input value in object or array on the controller

I have a few input fields being displayed programatically via the Ember each helper. These inputs are related to data being returned from my database, and I have a corresponding unique ID for each input that I could use if necessary.
My question is how can I store the value of these dynamically generated inputs on my controller so that I can access the user's input data? I was trying to do something like this:
{{#each solutionTypes as |solutionType|}}
{{input value=inputData[solutionType.id]}}
{{/each}}
However, trying to access an object or array in this manner causes a build error related to the the above syntax in specifying the value (object dot notation causes a build error too).
In short, I am trying to save the value of the input field as a property on an object or in an array instead of as a plain variable on the controller. I would like the input data from all of the inputs in the form to be accessible from the "inputData" variable in the following form:
{
"1000": "data from first input",
"1001": "data from second input",
"1002": "data from third input"
}
The primary issue is utilizing the dynamic keys (from solutionType.id) in the handlebars code without getting a build error.
If this is not possible using the value attribute but you know how to accomplish this with actions or with something else, I'm more than open to your ideas.
The question is a tad confusing so I'll answer in both ways I interpreted your question.
Two-way binding
The {{input}} helper establishes a two way binding with the value so in your example:
{{input value=solutionType.value}}
will bind the solutionType.value to the input. Not only will it display that value but it means as the user types into the input it will update solutionType.value.
One-way bindings (Data Down Actions Up)
Based on your use of inputData being different then solutionType I assume you want a one way binding.
The community standard is to use Data Down Actions Up in such that the solutionType.value does not change as the user enters data but instead sends an action back up so you can manage it as you see fit.
Unfortunately the current Ember {{input}} helper does not support this. There is an addon called ember-one-way-controls which will do this for you. You might want to experiment with that.
A caveat with the above addon is that you will have to manage the solutionTypes data manually as the actions come back up.
Ultimately you will have to decide just how tightly coupled the data you display via an input field is to the data you expect the user to type and adjust your design accordingly.
Yes. You can utilize the dynamic keys (from solutionType.id) in the handlebars code without getting a build error by using get and mut helper it's possible. ember-twiddle
For two way binding,
{{input value=(mut (get inputData (get solutionType 'id'))) }}
For one way binding,
{{input value=(get inputData (get solutionType 'id')) }}
routes/application.js
import Ember from 'ember';
export default Ember.Route.extend({
model(){
return [{id:'1000'},{id:'1001'},{id:'1002'}];
},
setupController(controller,model){
this._super(...arguments);
controller.set('solutionTypes',model);
}
});
controllers/application.js
import Ember from 'ember';
export default Ember.Controller.extend({
appName: 'Ember Twiddle',
inputData:{'1000': "data from first input", '1001': "data from second input",'1002': "data from third input"},
});
templates/application.hbs
<h1>Welcome to {{appName}}</h1>
<br>
<h1> One way binding </h1>
{{#each solutionTypes as |solutionType|}}
{{input value=(get inputData (get solutionType 'id')) }}
{{/each}}
<h2> Two way binding </h2>
{{#each solutionTypes as |solutionType|}}
{{input value=(mut (get inputData (get solutionType 'id'))) }}
{{/each}}
<br>
<h2> Result </h2>
{{#each solutionTypes as |solutionType|}}
<span> {{get inputData (get solutionType 'id')}} </span>
{{/each}}
<br />
{{outlet}}
<br>
<br>

How to use a component from within a component in Ember

G'day all,
I'm trying to wrap a component with another to provide a simplified editing wrapper.
The component is to conditionally show either a label or a select component that allows the user to pick the right value.
I want to wrap the power-select component, and pass it's values through to the sub-component, so the page template component reference looks like this:
{{cm-select
title="Country ##"
options=countries
selected=selectedCountry
searchField="name"
action="selectCountry"
}}
"countries" is an array of country objects, and selectedCountry is one of those country objects.
The component template has the following:
<td>{{title}}</td>
<td>
{{#if edit}}
{{#power-select
options=options
selected=selected
searchField=searchField
as |object|}}
{{object.name}}
{{/power-select}}
{{else}}
<small>{{modelElement}}</small>
{{/if}}
</td>
Unfortunately the power-select component renders with an empty list of options.
I thought wrapping those parameters in handlebars might do the trick, but it seems that handlebars in handlebars isn't a valid syntax.
Does anyone have any ideas?
Thanks,
Andy
That should work, I created a twiddle for you, demonstrating your use case. You'll see I updated the your cm-select template to this:
{{title}} |
<button {{action 'toggleEdit'}}>Toggle Edit</button>
<br/>
{{#if edit}}
Search for a Item via {{searchField}}
<br/>
{{power-select
options=options
selected=selected
searchField=searchField
onSelect=(action "itemSelected")
}}
{{else}}
{{search-list
options=options
searchField=searchField
onSelect=(action "itemSelected")
}}
{{/if}}
Where you iterated over options for power-select in the cm-select component, I moved that down into the power-select template. It's better to try and encapsulate some functionality there, instead of having everything in cm-select. I wasn't sure what you had in mind with {{modelElement}} so I just demonstrate what it would look like, using two different components in cm-select.

custom Handlebars helper - parameter is not resolved

# here is CreditCards controller context
{{#with controllers.currentCardCategory}}
{{#each property in cardProperties}}
{{#is property.symbol 'your_savings'}}
<td class="td">{{yourSavings}}</td>
{{else}}
<td class="td">{{cardProperty this property.symbol}}</td>
{{/is}}
{{/each}}
{{/with}}
I create the table dynamically. All content comes from ArrayController except one that is a computed property that comes from the controller. symbol' field is underscored likeannual_fee' and belongs to CreditCardProperty. Each card category has different set of card properties. Only two categories have properties (category has many card properties) and one record has computed field set to true. That means that the template should look up the corresponding controller.
As symbol (e.g age_to_apply) relates to one of the CreditCard fields (ageToApply) all I could to figure out was to use the cardProperty helper which takes current card in the context (this) and resolves property.symbol, e.g:
camelizedProperty = categoryProperty.camelize()
card.get 'camelizedProperty'
Ideally I'd like to do without the helper and use it somehow like this:
# *** {{property.symbol}} should look up this context
# and become e.g {{annual_fee}} or {{annualFee}} - is it possible?
{{#with controllers.currentCardCategory}}
{{#each property in cardProperties}}
<td class="td">{{property.symbol}}***</td>
{{/each}}
{{/with}}
But the problem is that I don't know how can I render that '{{yourSavings}}' part. The helper you can see comes from swag collection of Handlebars helpers. The helper, unfortunately does not resolve properties so that property.symbol becomes a string.
Here it is:
Handlebars.registerHelper 'is', (value, test, options) ->
if value is test then options.fn(#) else options.inverse(#)
I think it is possible but with the right helper - don't know which one, though.
What I do would like to avoid is to resort to computed property like if isYourSavings.
I am not certain about the context of your code, but it seems like you are looking for registerBoundHelper with a block helper. This isn't supported. You will run into this warning,
Assertion failed: registerBoundHelper-generated helpers do not support use with Handlebars blocks.
An alternative way to do what you are doing is to use a view helper instead. A view helper is like a helper but can render with a custom template.
For instance a CardItemView would be,
App.CardItemView = Em.View.extend({
templateName: 'cardItemTemplate'
});
Em.Handlebars.registerHelper('cardItem', App.CardItemView);
Where the cardItemTemplate is,
<script type='text/x-handlebars' data-template-name='cardItemTemplate'>
{{#if view.property.symbol}}
<td class="td">{{yourSavings}}</td>
{{else}}
<td class="td">{{cardProperty view.property.symbol}}</td>
{{/if}}
</script>
And you could use the helper like so,
{{#with controllers.currentCardCategory}}
{{#each property in cardProperties}}
{{cardItem property=property etc}}
{{/each}}
{{/with}}
You can pass in any number of properties as attributes. These will be bound to the CardItemView. And since it's a view anything a view does, like custom computed properties, can be done in CardItemView.

Controller not seeing the updated model - asynchronous handling

I have a very simple requirement but like with many things in Ember.JS, I'm banging my head against the wall trying to get it implemented.
I have an overview screen where a couple of records are displayed in a table.
To render the overview screen I'm using the following Route
App.LocationsIndexRoute = Ember.Route.extend({
setupController: function(controller) {
var locations = App.Location.find();
controller.set('content', locations);
},
renderTemplate: function() {
this.render('locations.index',{into:'application'});
}
});
This is working fine.
I would now like to conditionally render the overviewtable.
If records are present render the table.
If no records are present display a message.
I tried implementing this using the following controller.
App.LocationsIndexController = Ember.ArrayController.extend({
locationsPresent: function() {
var model = this.get('content');
return model.content.length > 0;
}.property()
});
and the following template
{{#if locationsPresent}}
<table class="table table-hover">
<tr>
<th>Latitude</th>
<th>Longitude</th>
<th>Accuracy</th>
<th></th>
<th></th>
</tr>
{{#each location in model}}
<tr>
<td>{{location.latitude}}</td>
<td>{{location.longitude}}</td>
<td>{{location.accuracy}}</td>
<td>{{#linkTo locations.edit location}}Edit{{/linkTo}}</td>
<td><button {{action removeItem location}}>Delete</button></td>
</tr>
{{/each}}
</table>
{{else}}
No locations present.
{{/if}}
The computed locationsPresent property is called once, before the page is rendered. At that time I assume that the model is still being loaded as the length = 0.
When the page is rendered, the locations from the App.Locations.find() are available but the locationsPresent is not called anymore, meaning the page decided to render the No locations present. message.
I went through the Managing Asyncrony in Ember page and assumed that the computer property locationsPresent would be updated if the underlying model changed (if it was completely loaded) as the page states :
Using a computed property for author eliminated the need to explicitly invoke the computation in a callback when the underlying property changed.
I'd love to know what I'm doing wrong and how I can fix this but more importantly why I seem to be missing some of these core concepts of Ember.JS. If somebody can point me where in the docs / guides this is explained properly I'd love to know.
I think it is a easy fix. You need to add the property you are observing. like so:
locationsPresent: function() {
var length = this.get('content.length');
return length > 0;
}.property('content.#each')
adding the #each is necessary if locationsPresent needs to recalculate wen content is added. I think you can also observe 'content.isLoaded'