Conditional #click with a method in vuejs - if-statement

This is my for loop:
<li v-for="(crumb, index) in breadcrumbs" :class="{ 'is-active' : index==breadcrumbs.length-1 }">
{{ crumb.name }}
</li>
#click="methodName" shouldn't be available for the last iteration.
I can check the last iteration with index==breadcrumbs.length-1
Is this possible using apply v-if?

There is a possibility by defining the event handler this way:
v-on="condition ? { eventName: () => handler } : {}"
The ?: operator can be used as a shortcut for an if...else statement
In your case it would be like this:
<li v-for="(crumb, index) in breadcrumbs" :class="{ 'is-active' : index==breadcrumbs.length-1 }">
<a href="javascript:void(0)" v-on="index < breadcrumbs.length-1 ? { click: () => methodName(parms) } : {click: ($event) => $event.preventDefault() }" >{{ crumb.name }}</a>
</li>
Small fiddle

Related

Sitecore not pulling through field values

Instead of the field value coming through I get 'No text in the field'. This is for all views that reference a field and isn't hard coded seemingly.
The content is there in the content editor, but not pulling through to the experience editor or the live web view. I've tried rebuilding the link databases, as well as using the GUID in the view to reference the field but no luck fixing this.
For example:
Local
Experience Editor on local
Content editor on local
Live
Experience Editor on live
#using Sitecore.Mvc
#using Sitecore.Data.Items
#using Sitecore.Mvc.Presentation
#model RenderingModel
#{
int counter = 0;
int maxvisible = 6;
// Count can be set in the control properties so the editors can vary the amount of cards showing
if (Html.Sitecore().CurrentRendering.Parameters["Count"] != null)
{
maxvisible = int.Parse(Html.Sitecore().CurrentRendering.Parameters["Count"]);
}
var UniqueName = "";
if (Html.Sitecore().CurrentRendering.Parameters["UniqueName"] != null)
{
UniqueName = Html.Sitecore().CurrentRendering.Parameters["UniqueName"];
}
var cardpanel = "cardpanel" + UniqueName;
UniqueName = "expandbutton" + UniqueName;
Item firstChild = Model.Item.Children[0];
}
<!--Adaptive code (as opposed to Responsive)-->
<!--html code for desktop version-->
<div class="container visible-lg visible-md visible-sm">
<div class="row row-eq-height">
#foreach (Item child in Model.Item.Children)
{
if (#Html.Sitecore().Field("ExcludeFromPage", child).ToString() != "1")
{
if (counter >= maxvisible)
{
if (counter == maxvisible)
{
#:<div class="#cardpanel" style="display: none;">
#:<div class="row-eq-height">
}
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-4 CardHeightMargin flexbox">
<div class="rcorners1">
<div class="col-xs-12 img-padding cardmobile top">
<div class="#Html.Sitecore().Field("{C63983F3-6ECD-45EA-A1D5-DFB37B366EDD}", child) scale-08"></div>
</div>
<div class="col-xs-12 CardHeight cardmobile bottom">
<h3>#Html.Sitecore().Field("{5787E6DD-A0F2-454F-AC4C-50921D4BBCB3}", child)</h3>
<p>#Html.Sitecore().Field("{1E900F2F-6F68-46B4-A98A-7BDF3CE06C5E}", child)</p>
</div>
</div>
</div>
}
else
{
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-4 CardHeightMargin flexbox">
<div class="rcorners1">
<div class="col-xs-12 img-padding cardmobile top">
<div class="#Html.Sitecore().Field("{C63983F3-6ECD-45EA-A1D5-DFB37B366EDD}", child) scale-08"></div>
</div>
<div class="col-xs-12 CardHeight cardmobile bottom">
<h3>#Html.Sitecore().Field("{5787E6DD-A0F2-454F-AC4C-50921D4BBCB3}", child)</h3>
<p>#Html.Sitecore().Field("{1E900F2F-6F68-46B4-A98A-7BDF3CE06C5E}", child)</p>
</div>
</div>
</div>
}
counter++;
}
}
#if (counter != 0 && counter > maxvisible)
{
#:</div>
#:</div>
<div class="center-block #UniqueName">
#Html.Sitecore().Field("Expand")
</div>
}
</div>
</div>
<!--html code for mobile version - Carousel-->
<div class="container visible-xs">
<div id=#Model.Item.Children[0].ID.Guid.ToString("N") class="carousel slide" data-ride="carousel">
<!-- Indicators -->
<ol class="carousel-indicators">
<li data-target="##Model.Item.Children[0].ID.Guid.ToString("N")" data-slide-to="0" class="active"></li>
#for (int itemcount = 1; itemcount < Model.Item.Children.Count; itemcount++)
{
<li data-target="##Model.Item.Children[0].ID.Guid.ToString("N")" data-slide-to=#itemcount></li>
}
</ol>
<!-- Wrapper for slides -->
<div class="carousel-inner m-y-1" role="listbox">
<div class="item mobilecardheight active">
<div class="col-xs-12 img-padding img-div-height">
<div class="#Html.Sitecore().Field("{C63983F3-6ECD-45EA-A1D5-DFB37B366EDD}", firstChild) scale-08"></div>
</div>
<div class="col-xs-12 CardHeight ">
<h3>#Html.Sitecore().Field("{5787E6DD-A0F2-454F-AC4C-50921D4BBCB3}", firstChild)</h3>
<div class="col-xs-12">
<p>#Html.Sitecore().Field("{1E900F2F-6F68-46B4-A98A-7BDF3CE06C5E}", firstChild)</p>
</div>
</div>
</div>
#foreach (Item child in Model.Item.Children)
{
if (child.ID != firstChild.ID)
{
if (#Html.Sitecore().Field("ExcludeFromPage", child).ToString() != "1")
{
<div class="item mobilecardheight">
<div class="col-xs-12 img-padding img-div-height">
<div class="#Html.Sitecore().Field("{C63983F3-6ECD-45EA-A1D5-DFB37B366EDD}", child) scale-08"></div>
</div>
<div class="col-xs-12 CardHeight">
<h3>#Html.Sitecore().Field("{5787E6DD-A0F2-454F-AC4C-50921D4BBCB3}", child)</h3>
<div class="col-xs-12">
<p>#Html.Sitecore().Field("{1E900F2F-6F68-46B4-A98A-7BDF3CE06C5E}", child)</p>
</div>
</div>
</div>
}
}
}
<!-- Left and right controls -->
<a class="left carousel-control" href="##Model.Item.Children[0].ID.Guid.ToString("N")" role="button" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="##Model.Item.Children[0].ID.Guid.ToString("N")" role="button" data-slide="next">
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
</div>
</div>
<!--More button javascript used on the desktop screens-->
#if (counter != 0 && counter > maxvisible)
{
<script>
var acc = document.getElementsByClassName("#UniqueName");
var i;
for (i = 0; i < acc.length; i++) {
acc[i].addEventListener("click", function () {
var panel = this.previousElementSibling;
if (panel != null) {
if (panel.style.display === "block") {
panel.style.display = "none";
this.innerHTML = "<a href='#policies' class='more_link'>Show more</a>";
} else {
panel.style.display = "block";
this.innerHTML = "<a href='#policies' class='more_link'>Show less</a>";
}
}
});
}
</script>
}
This was all working as expected on my local, but I must've changed something elsewhere that caused this. Any ideas?
Can you please add some more Screen shot? am not getting what content you exactly added in content editor.
Your field references look strange to me...
#Html.Sitecore().Field("{5787E6DD-A0F2-454F-AC4C-50921D4BBCB3}", child)
The parameters for #Html.Sitecore().Field() are:
string FieldName
string FieldName, Item item
string FieldName, object parameters
string FieldName, Item item, object parameters
Are your fields literally called "{5787E6DD-A0F2-454F-AC4C-50921D4BBCB3}" or is that just their ID? Your editor screenshot has the fields "CardText", "CardTitle", "CardIcon" and that's what I'd expect to see used instead of the GUIDs:
#Html.Sitecore().Field("CardTitle", child)
No idea why it'd be working on live though if what you showed is also what's deployed.

How to render element depends on selected option?

i'm newbie in react js , and i want to have a form with select options
i want that when user click on each option , each option render different elements
class Resepy extends Component {
state = {
Resepy : 'default'
}
render() {
return = (
<div className="Resepy">
<form>
<select id="id_field1" name="field1" onChange={(e) => this.state.Resepy = "Burger"}>
<option value="default">Food type not selected</option>
<option value="burger" onClick={(e) => this.setState({ Resepy: 'Burger' })}>Burger</option>
<option value="pizza" onClick={(e) => this.setState({ Resepy: 'Pizza' })}>Pizza</option>
</select>
<div className="food">
{ this.state.Resepy === "burger" ? <div className="burger"></div> //can return any html
: <div className="default">default</div>
}
<div className="pizza"></div>
<div className="food-detail"></div>
</div>
<button type="submit">Add to tray</button>
</form>
</div>
);
}
}
export default Resepy;
General ternary operator used for more readable code.
Like this:
<form>//can be any element
{ codition == true ? <div>It is true</div> //can return any html
: <div>It is false</div>
}
</form>
Tested, working. Problem was with onClick method option cannot invoke that event.
class Resepy extends React.Component {
constructor(props){
super(props);
this.state = {
selected : 'default'
};
}
setSelected = (event) => {
let select = document.getElementById("id_field1");
this.setState({selected: select.value});
//document.getElementById("test").innerHTML = select.value;
}
render() {
return (
<div className="Resepy">
<h1>Something</h1>
<form>
<select id="id_field1" name="field1" onChange={this.setSelected}>
<option value="default">Food type not selected</option>
<option value="burger">Burger</option>
<option value="pizza">Pizza</option>
</select>
<div id="test"></div>
<div className="food">{
(this.state.selected === "default") ?
<div className="default">Default</div>
: (this.state.selected === "burger") ?
<div className="burger">Burger</div>
: <div className="pizza">Pizza</div>
}</div>
<button type="submit">Add to tray</button>
</form>
</div>
);
}
}
I have a hard time understanding you, but the most likely thing you could be trying to achieve with the following code from your original question:
<div className="burger" Resepy={this.state.Resepy === 'burger'}></div>
is:
<div className="food">
<div className={this.state.Resepy} />
</div>
Working example (but I am using Hooks instead of a class component):
const App = () => {
const [selected, setSelected] = React.useState('default')
const handleChange = (event) => {
setSelected(event.target.value)
}
return (
<div>
<select value={selected} onChange={handleChange}>
<option>default</option>
<option>burger</option>
<option>pizza</option>
</select>
<div className="food">
<div className={selected}>{selected}</div>
</div>
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'))
.default { color: gray; }
.burger { color: orange; }
.pizza { color: red; }
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>
Now i want to render html elements depends on values , i tried this but it shows just [Object Object]
setSelected = (event) => {
let select = document.getElementById("id_field1");
document.getElementById("food").innerHTML =
select.value == "default" ?
<div className="default">Default</div>
: select.value == "Burger" ?
<div className="burger">Burger</div>
: <div className="pizza">Pizza</div>
}

How to avoid multiple ngIf in Angular's template

I'd like to know what is the best way to avoid using multiple *ngIf in template. For example, in a component's template, depends on the route, i have to generate multiple different elements like that:
<div *ngIf="route == 'page1'">Title for page 1</div>
<div *ngIf="route == 'page2'">Title for page 2</div>
<i *ngIf="route == 'page1'" class="fa fa-message"></i>
<i *ngIf="route == 'page2'" class="fa fa-bell-o"></i>
<div *ngIf="route == 'page1'">
<button>...</button>
</div>
<div *ngIf="route == 'page2'">
<div class="menu"></div>
</div>
It'll become messy soon, so i came up with a solution, in this component's ts file, i defined an array:
arr_1 = [
{ type: "text", content: "Title for page 1" },
{ type: "icon", class: "fa fa-message" },
{ type: "button", content: "..." }
]
arr_2 = [
{ type: "text", content: "Title for page 2" },
{ type: "icon", class: "fa fa-bell-o" },
{ type: "menu", menu_children: [...], class: "menu" }
]
In its template:
<div *ngIf="route == 'page1'">
<generator *ngFor="let ele of arr_1"
[type]="ele.type"
[class]="ele.class"
[content]="ele.content"
[menu_children]="ele.menu_children"
>
</generator>
</div>
<div *ngIf="route == 'page2'">
<generator *ngFor="let ele of arr_2"
[type]="ele.type"
[class]="ele.class"
[content]="ele.content"
[menu_children]="ele.menu_children"
>
</generator>
</div>
And i created a GeneratorComponent that receives the type and generate the corresponding element:
#Component({
selector: 'generator',
...
})
export class GeneratorComponent {
#Input() type: string;
#Input() content: string;
#Input() class: string;
#Input() menu_children: string;
}
GeneratorComponent's template:
<div *ngIf="type == 'text'">{{ content }}</div>
<i *ngIf="type == 'text'">{{ content }}</i>
...
The problem here is the class GeneratorComponent will have multiple properties and they are not used for one reason (for example: content and menu_children have no relation).
Do you have any idea to fix my solution ? Other solutions will be appreciated.
Thanks !
You could use the helper element <ng-container>. It allows to apply structural directives *ngIf, *ngFor, ..., without actually adding an element to the DOM
<ng-container *ngIf="route == 'page1'">
<div>Title for page 1</div>
<i class="fa fa-message"></i>
<div>
<button>...</button>
</div>
</ng-container>
<ng-container *ngIf="route == 'page2'">
<div>Title for page 2</div>
<i class="fa fa-bell-o"></i>
<div>
<div class="menu"></div>
</div>
</ng-container>
<div [ngSwitch]="route">
<generator ngSwitchWhen="page1" *ngFor="let ele of arr_1"
[type]="ele.type"
[class]="ele.class"
[content]="ele.content"
[menu_children]="ele.menu_children">
</generator>
<generator ngSwitchWhen="page2" *ngFor="let ele of arr_2"
[type]="ele.type"
[class]="ele.class"
[content]="ele.content"
[menu_children]="ele.menu_children">
</generator>
</div>
If it depends on route, why not have two components and display the right one based on the current route via router-outlet
i.e. have a Page1Component and Page2Component and configure routes for them in the appropriate routing.ts file
[
..
{
path: 'page1',
component: Page1Component,
},
{
path: 'page2',
component: Page2Component,
},
]
Then each Page component can define exactly what should be displayed.

AngularJS with list

I'm doing an employees list that is loaded from SQLite database. I don't know why my list is empty, but I can see via JSON.stringify that data is comming.
I'm using AngularJS and Cordova Framework. Debugging with Ripple.
listEmployees.html
<div data-role="page" apply-jq-mobile>
<div data-theme="a" data-role="header">
<h3>
Header
</h3>
</div>
<div data-role="content">
<div class="ui-grid-a">
<div class="ui-block-a">
</div>
<div class="ui-block-b">
<a data-role="button" href="#/new" data-icon="plus" data-iconpos="left">
New
</a>
</div>
</div>
<input type="text" ng-model="search" class="search-query" placeholder="Search">
<ul data-role="listview" data-divider-theme="b" data-inset="true">
<li data-role="list-divider" role="heading">
Employees
</li>
<li data-theme="c" ng-repeat="employee in employees">
{{employee.name}}
</li>
</ul>
</div>
</div>
EmployeeCtrl
function EmployeeCtrl($scope, Employee){
$scope.employees = Employee.getAllEmployees();
$scope.saveEmployee = function(id) {
if(id){
//TODO
} else {
Employee.addEmployee($scope.employee);
}
}
}
Employee
app.factory('Employee', function() {
var data = {};
data.addEmployee = function(_employee, callback) {
var employee = new Employee();
employee = _employee;
DbService.db.employees.add(employee);
DbService.db.saveChanges(callback);
}
data.getAllEmployees = function() {
DbService.db.employees.toArray(function(employees) {
console.log(JSON.stringify(employees));
return employees;
});
};
return data;
});
I think you need to use promises. Your call to db is asynchronous and therefore view is getting rendered before your data arrives.
data.getAllEmployees = function() {
var $d = $q.defer();
DbService.db.employees.toArray(function(employees) {
console.log(JSON.stringify(employees));
$d.resolve(employees);
});
return $d.promise;
};
Angular templating system wait for all the promises to get resolved before rendering. So I think this will solve your problem.
So, I solved it.
function EmployeeCtrl($scope, Employee){
Employee.getAllEmployees(function(employees){
$scope.employees = employees;
$scope.$apply();
});
}
.
app.factory('Employee', function() {
var data = {};
data.getAllEmployees = function(callback) {
DbService.db.employees.toArray(function(employees) {
callback(employees);
});
};
return data;
});
Thank you all!

{{bindAttr }} {{action}} [Object] Has no method replace

when ember.js tries to render my template containing the following bindAttr. the following exception is thrown in handlebars.js
Uncaught TypeError: Object [object Object] has no method 'replace' handlebars.js:848
bind attr tag:
<div class="postWrapper" {{bindAttr style="display:none"}}>
Update
this also happens when i use the action helper
<div {{action Toggle}} class="btn pull-right">
<i class="postToggler icon-chevron-down " ></i>
</div>
Update Full Code
Template
<script type="text/x-handlebars" data-template-name="Composer">
<div class="postWrapper">
<div class="postContentWrapper" {{bindAttr style="controller.display"}}>
<div class="row-fluid">
<div class="pull-left span10">
To :
<input id="test2" type="text" style="margin-top: 7px;width:90%" />
</div>
<div {{action Toggle}} class="btn pull-right">
<i class="postToggler icon-chevron-down " ></i>
</div>
</div>
<div class="row-fluid" style="height:100%" >
<div id="wmd-button-bar" style="width:48%;display:inline-block" ></div>
<div class="pull-right">
<a>Hide preview</a>
</div>
<div class="wmdWrapper" style="height:80%">
<div class="wmd-panel" style="vertical-align: top;">
<textarea class="wmd-input" id="wmd-input" style="height: 100%;"></textarea>
</div>
<div id="wmd-preview" class="wmd-preview pull-right"></div>
</div>
<br />
</div>
<div class="row-fluid">
<div class="span6 ">
<p>
Tags :
<input id="test" type="text" style="width:80%"/>
</p>
</div>
<div class="span2 pull-right">
<button id="btnSubmitPost" class="btn btn-success pull-right">{{controller.buttonText}}</button>
<button id="btnCanelPost" class="btn btn-warning pull-right">Cancel</button>
</div>
</div>
<div class="row-fluid">
</div>
</div>
</div>
</script>
View and render
/*
MODES
NEW
REPLY
*/
Thoughts.ComposerController = Ember.Object.extend({
mode: 2,
visible: false,
messageContent: "",
buttonText: function () {
switch (this.get("mode")) {
case 1: return "Post";
case 2: return "Reply";
}
}.property(),
display: function () {
if (this.get("visible")) {
return 'display:block';
} else
return 'display:none';
}.property(),
Toggle: function(){
console.log('Helllo');
}
});
Thoughts.ComposerController = Thoughts.ComposerController.create();
Error Information
object dump
string: "data-ember-action="1""
__proto__: Object
constructor: function (string) {
toString: function () {
__proto__: Object
Crashes on the replace method, because the method replace is undefined
Handlebars.Utils = {
escapeExpression: function (string) {
// don't escape SafeStrings, since they're already safe
if (string instanceof Handlebars.SafeString) {
return string.toString();
} else if (string == null || string === false) {
return "";
}
if (!possible.test(string)) { return string; }
----> return string.replace(badChars, escapeChar);
},
So first of all you need to define only need to define the controller. You don't have to create an instance. Ember will do it for you when application initialize.
If you define a property that is observing another in other words its value depends on another, you need this to specify as parameter to property helper.
Thoughts.ComposerController = Ember.Controller.extend({
mode: 2,
visible: false,
messageContent: "",
buttonText: function () {
switch (this.get("mode")) {
case 1: return "Post";
case 2: return "Reply";
}
}.property('mode'),
display: function () {
return 'display:' + this.get('visible') ? 'block' : 'none';
}.property('visible'),
Toggle: function () {
this.toggleProperty('visible');
this.set('mode', this.get('mode') == 2 ? 1 : 2);
}
});
Template itself seems valid.
You can get this working by creating a composer route like this:
this.route('composer');
or by rendering it in another template like this:
{{render 'composer'}}
That should be answer to your question. BUT
Wouldn't be better to use {{if}} helper for showing some content inside of template based on a condition?
i finally found some time to work on this again.
all i did was replace the ember and handlebars js files, and the code is working fine now thanks