Conditionally setting configs in ExtJS 6? - if-statement

I have an Ext.Img that I would like to set the src config of based upon a condition. Is there a simple way to accomplish this? I am thinking something like
if(condition){ src: 'image1.png'} else { src: 'image2.png'}
but this obviously won't work. I've using some of the techniques mentioned in this thread, by adding a different image item based on the condition but all I get are errors or no items will be added to the parent panel.

Javascript supports the so-called conditional (ternary) operator:
condition ? expr1 : expr2
which in your example would be
src: condition?'image1.png':'image2.png'
I use this regularly, e.g. to account for varying space requirements of the different themes:
width: Ext.is.Triton?200:180
However, you have to make sure that the variables used in the condition are correctly defined at the time they are evaluated (this may be earlier than you think).
If you need conditions that are re-evaluated whenever the variables change, you have to look into ExtJS bindings.

You can easily just have the configuration ready beforehand in a variable, for example:
// Set the default value (image 1)
var imageUrl = 'image1.png';
if (condition)
{
// Condition for image 2 is met, set it
imageUrl = 'image2.png';
}
var myConditionalImage = Ext.create('Ext.img', {
...
// Use prepared variable with conditional image URL
src: imageUrl
});

Related

Direction-aware transition with Ember Liquid Fire's {{liquid-with}} helper

In my Ember app, I would like to make nice Liquid Fire transitions within the same route when the model of a dynamic route changes. Here's my router:
// app/router.js
Router.map(function() {
this.route("campaigns", { path: "/" }, function() {
this.route("campaign", { path: "/campaign/:election_year" });
});
});
I would like the view to leave the screen to the left when switching to an election_year that is in the future (e.g., from campaign/2008 to campaign/2012) and to the right the other way around.
My first thought was to use use the {{liquid-outlet}} and the toModel function in the app/transitions.js file, but Edward Faulkner (creator of Liquid Fire) says in this thread that
liquid-outlet does not handle model-to-model transitions on the same
route
and that I should use {{liquid-with}} instead. However I'm at a loss as to how to handle the directionality, i.e. make the view go left when election_year increases, and go right when it decreases. Any clues?
When using a liquid-with (or liquid-bind) helper, there is not necessarily a route or model involved in the animation, and so constraints like toRoute or toModel do not apply. Instead, you can use toValue which will match against whatever you're passing into the helper.
Assuming you're passing a Campaign model to liquid-with, you could use a rule like this in transitions.js:
this.transition(
this.toValue(function(newValue, oldValue) {
return newValue instanceof Campaign &&
oldValue instanceof Campaign &&
newValue.electionYear > oldValue.electionYear
}),
this.use('toLeft'),
this.reverse('toRight')
)
Explanation:
We have a constraint, an animation to use when it matches (toLeft), and an animation to use when it matches with "to" and "from" reversed (toRight),
All the rule constraints (including toValue, fromRoute, etc) can accept:
simple values like toValue(42) or toRoute('posts') that will be compared with ===
regular expressions like toRoute(/unicorn/)
functions that test the value, like toValue(n => n > 1).
functions that compare the value and the "other value", like
toValue((newThing, oldThing) => newThing.betterThan(oldThing))
The final case is what we're using in the solution above.
(We are continuing to refine these APIs. In this particular case, I think we should add an explicit name for the comparison rule, like this.compareValues(function(oldValue, newValue){...}), instead of just overloading toValue to also do comparison. But this should not affect your solution, as I'm not going to break the existing behavior in the foreseeable future.)

Ember's volatile and templates

I have a property mood which is part of the interface for a component. Behind the scenes I have a computed property called _mood:
const { computed, typeOf } = Ember;
_mood: computed('mood','A','B','C' function() {
let mood = this.get('mood');
if (typeOf(mood) === 'function') {
mood = mood(this);
}
return !mood || mood === 'default' ? '' : `mood-${mood}`;
}).volatile(),
I have a situation where with the volatile() that hangs of of Ember's computed object resolves all non DOM unit tests successfully but for some reason it is not triggering the template to update the DOM under any circumstance. It should, at the very least, update if any of properties being watched change (in this case ['mood','A', 'B', 'C']) change. Because it is volatile (aka, doesn't cache results) the new results would show up in a template if the template knew to re-render the component but for some reason it doesn't.
If I remove the volatile() tag it works fine for static/scalar values but if mood is a function then the result is cached and therefore it only works once (not a working solution for this problem).
How do I get the best of both worlds?
I'm still not sure why the volatile() method is turning off updates to templates. This might be a real bug but in terms of solving my problem the important thing to recognise was that the volatile approach was never the best approach.
Instead the important thing to ensure is that when mood comes in as a function that the function's dependencies are included in the CP's dependencies. So, for instance, if mood is passed the following function:
mood: function(context) {
return context.title === 'Monkeys' ? 'happy' : 'sad';
}
For this function to evaluate effectively -- and more importantly to trigger a re-evaluation at the right time -- the title property must be part of the computed property. Hopefully that's straight forward as to why but here's how I thought I might accommodated this:
_moodDependencies: ['title','subHeading','style'],
_mood: computed('mood','size','_moodDependencies', function() {
let mood = this.get('mood');
console.log('mood is: %o', mood);
if (typeOf(mood) === 'function') {
run( ()=> {
mood = mood(this);
});
}
return !mood || mood === 'default' ? '' : `mood-${mood}`;
}),
That's better, as it allows at build time for a static set of properties to be defined per component (the _mood CP for me is part of a mixin used by a few components). Unfortunately this doesn't yet work completely as the it apparently doesn't unpack/destructure the _moodDependencies.
I'll get this sorted and update this unless someone else beats me to the punch.

angularjs ui-router: find level of current state

So I'm using ui-router and stateparams to nest child states, and it works well. I'm now trying to find a way to dictate a css class what state level the app is at. main.route1.section1 would be 3 levels.
Here's some non-working code to help show:
<div ng-class="{findState().currentCount}"></div>
app.run(function($rootScope, $state, $stateParams) {
$rootScope.$state = $state;
$rootScope.$stateParams = $stateParams;
$rootScope.findState = function() {
var currentName = $state.current.name;
var currentMatch = currentName.match(/./g);
$rootScope.currentCount = currentMatch.length;
};
});
I'm basically looking for a way to take $state.current.name which say equals main.route1.section1 and split it at the dot and count how many are in the array and return that number to the mg-class. Unless you have a better idea... like a regex filter?
Take a look of the object $state.$current (instead of $state.current). In particular, the property path : it's an array representing the state hierarchy of the current state.
So what you are looking for is : $state.$current.path.length

PlayFramework 2.0 - Not able to call functions from other templates

I want to place some helper functions in another file, since they will be overly reused. I took the Computer-Databse sample's listing file:
https://github.com/playframework/Play20/blob/master/samples/scala/computer-database/app/views/list.scala.html
I created a new file, called "listing.scala.html" under the app/views package, and moved the #link function from the original file to it. This new file looks like this:
#(currentSortBy: String, currentOrder: String, currentFilter: String)
#****************************************
* Helper generating navigation links *
****************************************#
#link(newPage:Int, newSortBy:String) = #{
var sortBy = currentSortBy
var order = currentOrder
if(newSortBy != null) {
sortBy = newSortBy
if(currentSortBy == newSortBy) {
if(currentOrder == "asc") {
order = "desc"
} else {
order = "asc"
}
} else {
order = "asc"
}
}
// Generate the link
routes.Application.listPerfil(newPage, sortBy, order, currentFilter)
}
So, on my original file, I replaced the #link call, with this one:
#title
And the problem is, when I try to compile I get this error:
value link is not a member of play.api.templates.Html
But according to the documentation (http://www.playframework.org/documentation/2.0.4/ScalaTemplateUseCases) it seems to be ok.
Any guess?
Play's templates aren't the best place for placing advanced conditions, most probably you'll get better flexibility by processing it in some controller (or other method) which will return you only required link
ie.:
#title
In your case proposed link(...) function of Application controller can also return a reverse-route.
Keep in mind that including other templates is best option for repeating blocks of HTML but sometimes it's hard to get specified string (mainly because of not trimmed spaces). As you can see there is also problem with calling nested functions. Most probably you can generate whole A tag in the listing.scala.html however using it isn't comfortable enough (IMHO).

Ignore or replace Handlebars blocks that don't compile

In a handlebars template in Ember.js, I have blocks like the following:
{{content.some_attribute}}
{{content.some_other_attr}}
{{content.more_attr}}
Some of these attributes don't exist and I'm implementing them slowly.
Is there a way to get these templates to compile and either ignore the blocks that don't evaluate or better yet, replace them with a html element so they're easier to spot in the browser?
(the template is pretty large and it's being converted from ERB slowly,
Is there a way to get these templates to compile and either ignore the blocks that don't evaluate
Properties that don't exist are undefined, and don't get rendered at all. In other words {{thisDoesNotExist}} will simply be invisible -- it will compile just fine.
or better yet, replace them with a html element so they're easier to spot in the browser
As Cory said, you could use a helper for this that checks for undefined, using Ember.Handlebars.registerBoundHelper.
This seems like a perfect case for a handlebars helper. The helper could validate the value and return the value or the html that you desire.
The following code should be used very carefully, since it has not been tested within an application.
A possible solution to replace the possible undefined value in a template is to overwrite Ember.getPath, which is used to lookup the value of a path in a template, see http://jsfiddle.net/pangratz666/hKK8p/:
var getPath = Ember.getPath;
Ember.getPath = function(obj, path) {
var value = getPath(obj, path);
return (Ember.none(value) ? 'OMG %# is not defined!!'.fmt(path) : value);
};
If this code would be used temporarily in an application, I would also restrict the check for undefined values to a specific obj. So something along those lines:
App.objectWhichHasUndefinedProps = Ember.Object.create({
...
});
Ember.View.create({
templateName: 'templateWithAttributes',
objBinding: 'App.objectWhichHasUndefinedProps'
}).append();
var getPath = Ember.getPath;
Ember.getPath = function(obj, path) {
var value = getPath(obj, path);
if (obj === App.objectWhichHasUndefinedProps) {
return (Ember.none(value) ? 'OMG %# is not defined!!'.fmt(path) : value);
}
return value;
};