Consider the following code:
class StoreController
constructor: ->
#products = gems
current_id = 0
for product in #products
if product.images?
for img in product.images
img.id = current_id
current_id += 1
gems = [
{
name: 'Dodecahedron'
images: [
{
full: "assets/img0.gif"
}
{
full: "assets/img1.gif"
}
]
}
{
name: 'Gemmy Gem'
}
{
name: 'Pentagonal Gem'
}
]
Is there a better way to write the nested for loops to check for product.images? without that if product.images? line?
EDIT:
The accepted answer below does actually answer this question. However, I decided to change the way I am writing my code to use a custom filter instead.
In filter.js.coffee , I wrote the following:
filterMod = angular.module 'storeFilters', []
current_id = 0
filterMod.filter 'addIds', ->
return (items) ->
# avoid $rootScope:infdig
return items if !items? || items.processed
for img in items
img.id = current_id
current_id += 1
items.processed = true
return items
The HTML goes below, notice the use of addIds in the inner ng-repeat
<div ng-controller="StoreController as store">
<ul ng-repeat="product in store.products" class="list-group">
<li class="list-group-item">
<h3> {{product.name}} <em class="pull-right">{{product.price | currency }}</em></h3>
<div class="gallery">
<div ng-repeat="img in product.images | addIds ">
{{img.id}}
<img ng-src="{{img.full}}"/>
</div>
</div>
<p> {{product.description}}</p>
<button ng-show="product.canPurchase">Add to Cart</button>
</li>
</ul>
</div>
And for the sake of completeness, here goes app.js.coffee
app = angular.module 'store', ['storeFilters']
app.controller 'StoreController',
class StoreController
constructor: ->
#products = gems
gems = []
You can use when condition in a loop:
for product in #products when product.images?
for img in product.images
img.id = current_id
current_id += 1
You need to check if product.images is not null like you do now for the loop, otherwise you will have an error. The example here shows what I am talking about.
Cheers!
I'm not sure what your current id's look like (either starting from a random number or from 0 to the length of the images), but you could just grab the index within the for loop and do this:
for product in #products when product.images?
img.id = current_id + i for img, i in product.images
or if its just the index:
for product in #products when product.images?
img.id = i for img, i in product.images
or to be cool:
img.id = i for img, i in product.images for product in #products when product.images?
Related
For example
Case 1 : <p></br></br></br></br></br>Sample Content</br>This is next line</br></br></br></br></br></br></p>
Result : <p>Sample Content</br>This is next line</p>
Case 2 : <p></br></br>Sample Content</p>
Result : <p>Sample Content</p>
Case 3 : <p></br></br></br>Sample Content</br></br></br>This is next line</br></br></br></br></br></br></p>
Result : <p>Sample Content</br></br></br>This is next line</p>
If you mean the following with 'unnecessary': a br tag that is right after or before an other tag you can use the following code. This code will result in the desired output you have in your question (Edit: except for Case 3, which was added after I answered this question).
function trimSource(inputElemId="input", outputElemId="output") {
let input = document.getElementById(inputElemId).innerHTML;
let output = input;
do {
input = output;
output = input.replaceAll("><br>", ">").replaceAll("<br><", "<");
} while (input!=output);
document.getElementById(outputElemId).innerHTML = output;
}
.input, .output {
display: block;
border: 1px solid black;
}
<button onclick="trimSource()">Click here to 'Trim' input to output</button><br>
output:<br>
<span id="output" class="output"></span>
input:<br>
<span id="input" class="input">
<p></br></br></br></br></br>Sample Content</br>This is next line</br></br></br></br></br></br></p></span>
I want to write in less code a function that will add the active classname and automatically removes all the other active class names. But there is also a unique class name needed for JavaScript in my case. But want to put that all in class name. How can I make this a valid classname. Is there a way to do that so it will not conflict with each other.
<ul class="three">
<li
v-for="(post, index) in listData.data"
:key="index"
:class="'list-item unordered-list ' + post.name.toLowerCase() + { active : activeName == post.name}"
#click="showInfo(post.name, post.description)">
{{ post.name }}
</li>
</ul>
Have a look at the object syntax or array syntax of class binding, which allows binding to an object or array returned by a value. That way you can simplify complex class or style combinations by calling a function from the template, like the example from the docs:
<div v-bind:class="classObject"></div>
...
data: {
isActive: true,
error: null
},
computed: {
classObject: function () {
return {
active: this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}
<ul class="three">
<li
v-for="(post, index) in listData.data"
:key="index"
:class="['list-item', 'unordered-list ', post.name.toLowerCase(), { active: activeName == post.name }]"
#click="showInfo(post.name, post.description)">
{{ post.name }}
</li>
</ul>
In Mason i could define a filter:
<%filter Div($class)>
<div class="<% $class %>">
<% $yield->() %>
</div>
</%filter>
And later i could use it
% $.Div("row") {{
1 The "$yield->()" method returns everything from here (free text)
% $.Div("col") {{
2 even could have another nested filter, etc...
% }}
% }}
with result
<div class="row">
1 The "$yield->()" method returns everything from here (free text)
<div class="col">
2 even could have another nested filter, etc...
</div>
</div>
E.g. the $yield->() method returns everything what is inside of the enclosed filter.
Want achieve same functionality using Text::Xslate, but don't know how.
The closest thing what I found ,are the macro blocks where i could write:
: macro div -> ($cls,$str) {
<div class="<: $cls :>">
<: $str :>
</div>
: }
and use it as
: div("row",
: div("col",
: "my string"
: )
: )
but the my string must be quoted and : marked, so it is impossible to use any free html text. E.g. the following dies.
: div("row",
some free text here
: div("col",
nested
here
: )
: )
After the long introduction, the question is simple:
Exists in the Text::Xslate something as the Mason's $yield->() call, which returns the content of the enclosed filter call? (or if not exists, how i could mimic it?)
this script works in jQuery 1.9, but does not work in 1.8. How to convert this script to jQuery 1.8 ?
NOT Working Demo on jsfiddle
Working Demo on jsfiddle
HTML
<div id="container">
<div id="c1" class="aaa" style="text-align:right; color:red top:100px; ">child 1</div>
<div id="c2" class="aaa" style="text-align:left; top:200px; ">child 2</div>
</div>
jQuery script
$("#container").children().each( function () {
alert("element ID = " + $(this).attr('id'));
var styleProps = $(this).css(["width",
"height",
"color",
"background-color",
"text-align",
"left",
"top",
"right",
"bottom"]);
$.each(styleProps, function (prop, value) {
alert(prop + " = " + value);
});
});
The css function accepting an array wasn't implemented until 1.9.
You'll probably have to do it by hand if you're using 1.8 (loop through the values one at a time).
var styleNames = ["width", "height", "color", ...etc... ];
var i;
var $elem = jQuery(this);
for (i = 0; i < styleNames.length; ++i) {
alert(styleNames[i] + " = " + $elem.css(styleNames[i]));
}
I have an ajax form which which is currently returning errors using the S.error() method. This is fine but I also want to add a new css class to one of the elements parent div tags. I have tried to do this with the JE.Call() method with no avail. Is anyone could point me in the right direction it would be really appreciated.
Snippet Code
class Register {
private var user = User.createRecord
private var pw2 = ""
private var dob = ""
private var errors = new Array[String](7)
val whence = S.referer openOr "/"
Thread.sleep(400)
def registerUser(): JsCmd = {
errors(0) = User.validateUsername(user.username.is)
errors(1) = User.validateEmail(user.email.is)
errors(2) = User.validatePhone(user.phone.is)
errors(3) = User.validateCity(user.city.is)
errors(4) = User.validateDOB(dob)
errors(5) = User.validatePassword(user.uPw.is)
errors(6) = User.validateSecondPW(user.uPw.is, pw2)
if(errors.count(_ != "") == 0) {
user.uPw.set(User.hashPassword(user.uPw.is, user.id.is.toString))
user.dob.set(User.stringToDate(dob))
user.save
println("User id " + user.id.is.toString + " added to database")
S.redirectTo(whence)
}else{
if(errors(0) != "")
S.error("username-error", errors(0))
JE.Call("addError(username-error)")
......
}
}
def form = {
"id=username" #> SHtml.text("", user.username.set(_), "placeholder" -> "Username") &
"id=email" #> SHtml.email("", user.email.set(_), "placeholder" -> "Email") &
"id=phone" #> SHtml.text("", user.phone.set(_), "placeholder" -> "Tel") &
"id=city" #> SHtml.text("", user.city.set(_), "placeholder" -> "City") &
"id=dob" #> SHtml.text("", dob = _, "placeholder" -> "DOB") &
"id=password" #> SHtml.password("", user.uPw.set(_), "placeholder" -> "Password") &
"id=passwordCheck" #> SHtml.password("", pw2 = _, "placeholder" -> "Confirm Password") &
"type=submit" #> SHtml.ajaxSubmit("Register", () => registerUser, "class" -> "btn")
}
}
HTML Template
<h2>Register</h1>
<form class="lift:form.ajax?class=form-horizontal">
<div class="lift:Register.form">
<div id="id1" class="control-group">
<label class="control-label" for="username">Username:</label>
<div class="controls">
<input id="username">
<span id="username-error" class="help-inline"></span>
</div>
</div>
<div class="controls">
<button type="submit" ></button>
</div>
</div>
</form>
Javascript Function
<script>
function addError(id) {
$("#"+id).closest(".control-group").addClass("error");
}
addError("email-error")
</script>
Try to change the Call function.
JE.Call("addError","username-error").cmd
I recommend giving up on JavaScript abstractions in Lift and use plain Run Object everywhere. So In your case I'd use:
Run("addError(username-error)")