Remove the first item on click in Ractive.js - ractivejs

I have a list of 4 items and I need to remove the first item every time the button is clicked. I implemented a simple solution based on splice method but it seems to work only on the first click. Any further click doesn't change a thing.
Here is the html:
<script type="text/ractive" id="template1">
{{#each Posts}}
<div style="background-color: red">{{Text}}</div>
{{/each}}
<button on-click="removeFirst">Remove first</button>
</script>
<main></main>
, javascript:
var ractive1 = new Ractive({
template: '#template1',
el: 'main',
data: {
Posts: [ {Text: "Post 1"}, {Text: "Post 2"}, {Text: "Post 3"}, {Text: "Post 4"} ],
}
});
ractive1.on({
removeFirst: function() {
ractive1.splice('Posts', 0, 1, []);
}
});
and jsfiddle demo.

When you call splice on an array, the first argument is the index from which to start removing elements, the second argument is the number of elements to remove, and all the rest are items to insert into the array at the same location. So what you're actually doing when you call array.splice(0, 1, []) is replacing the first item with an empty array, instead of just removing it.
Ractive's array mutation methods follow the same form, except that the first argument is the 'keypath' of the array. So if you do this...
ractive1.splice('Posts', 0, 1);
...it works correctly.

Related

EnjoyHint - can I have a hint without specifying an element?

I'd like to have an introductory hint in EnjoyHint that the user can move on from by simply pressing "Next". So no arrow to an element. Is this possible?
HTML
<div class="hidden"></div>
JS
var enjoyhint_script_steps = [
{
'click .hidden': '<h2>Introduction</h2><p>This is an introductory sentence, which tells you a bit about everything.</p>',
showSkip: false,
showNext: true,
margin: 0,
onBeforeStart: function () {
document.getElementsByClassName('enjoyhint_svg_wrapper')[0].style.display = 'none';
}
},
{
onBeforeStart: function () {
document.getElmentsByClassName('enjoyhint_svg_wrapper')[0].style.display = 'block';
},
...rest of step 2...
}
...rest of steps...
];
Explanation
<div class="hidden"></div> is an empty element for EnjoyHint to target.
'click .hidden': '...description...' targets the empty element and adds a description.
showSkip: false hides the skip button.
showNext: true shows the next button.
margin: 0 hides the area highlighted by EnjoyHint.
onBeforeStart: function () {...} is used to hide the arrow in the first step and show it in the second step.
var enjoyhint_script_steps = [
{
'next .hidden': '<h2>Introduction</h2><p>This is an introductory sentence, which tells you a bit about everything.</p>',
showSkip: false,
showNext: true,
onBeforeStart: function () {
$('#enjoyhint_arrpw_line').hide();
}
},
{
...rest of step 2...
}
...rest of steps...
];
Explanation
There is a better solution then target to a hidden div, when assigning the 'click' event.
The 'click' event expects the user to click on the highlithed element in order to move on to the next step and when your element is hidden you cannot click on it.
In order to have 'Next' button by default and target the user to click on it you need to use the 'next' event.
The onBeforeStart gives you the option to run any function you want just before this specific hint starts, so you can run:
function () {
$('#enjoyhint_arrpw_line').hide();
}
Inside the onBeforeStart.
When you do it like that you can highlight any element on page without an arrow and have a mandatory 'Next' button.
You can also write it that way if it's more readable:
var enjoyhint_script_steps = [
{
event: 'next',
selector: '.hidden', // or any element you want to highlight
description: '<h2>Introduction</h2><p>This is an introductory sentence, which
tells you a bit about everything.'</p>
showSkip: false,
showNext: true, // not necessary
onBeforeStart: function () {
$('#enjoyhint_arrpw_line').hide();
}
},
{
...rest of step 2...
}
...rest of steps...
];
You can make div class="hidden" and make arrow transparent
let enjoyhint_script_steps = [
{
'click .hidden': '<h2>Hello</h2>',
arrowColor:'transparent'
}
];

Ui-select ng-model is not binded with selected

I am trying to do a simple drop down menu with a search in it.
I cant get the ng-model to be changed on this drop down.
this is what I have done, and as you can see its very simple (mostly copy paste from the get started)
I couldnt find any info about the $select. Is the problem is because I didnt add this to the ng-model? if so, what should I add to the controller
<div class="form-group">
<label class="col-md-1">Investigation type<font color="red"><b>*</b></font></label>
<div class="col-md-3">
<ui-select ng-model="investigationType" ng-change="someFunc()" theme="bootstrap">
<ui-select-match placeholder="Select or search a contries in the list...">
<span>{{$select.selected.name}}</span>
</ui-select-match>
<ui-select-choices repeat="item in contries | filter: $select.search">
<div ng-bind-html="item.name | highlight: $select.search"></div>
</ui-select-choices>
</ui-select>
</div>
</div>
{{investigationType}}
as you can see, very simple thing, though after selected I dont see anything on the page. whats wrong?
app.controller('investigationCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.investigationType ="";
$scope.toolShow=false;
$scope.someFunc = function () {
$scope.investigationType == "Alabama")
$scope.toolShow = true;
else
$scope.toolShow = false;
}
$scope.contries = [
{ id: 1, name: "Alabama" },
{ id: 2, name: "Alaska" },
{ id: 3, name: "Arizona" },
{ id: 4, name: "Arkansas" }];
}]);
You need ng-model to hold the selected object, not a string.
Rewrite to ng-model="contries.selected" (while contries is you data array).
Then add {{contries.selected}} to your template, you will see a serialization of your selected object, so just use contries.selected.name to access your item name.
Here is a working plunk
You can also do something like
ng-change="someFunc($select.selected)"
To access your selected object from the callaback, then you can avoid messing with the ng-model.

Meteor C3 charts based on D3 - multiple charts?

EDIT: clone this repository for a non working reproduction. https://github.com/FickleLife/meteor-c3-test
I am using https://github.com/peernohell/meteor-c3.js/
I pull two examples off the C3 site http://c3js.org/examples.html and can get them to display once on the page, but when I try to add a second on the same page the first disappears. There's no console error and the javascript variables are different.
chart 1 html template:
<template name="chart_cp_overview">
<div id="cpOverview"></div>
</template>
chart 1 js helper:
Template.chart_cp_overview.rendered = function () {
var cpOverview = c3.generate({
data: {
columns: [
['data1', 30, 200],
['data2', 130, 100]
],
type: 'bar',
groups: [
['data1', 'data2']
]
},
grid: {
y: {
lines: [{value:0}]
}
}
});
}
chart 2 html template:
<template name="chart_status">
<div id="chart"></div>
</template>
chart 2 helper:
Template.chart_status.rendered = function() {
var chart = c3.generate({
data: {
columns: [
['Dropped', 30],
['On Course', 120],
['DNS', 20],
['Finished', 40]
],
colors: {
'Dropped': '#E60000',
'On Course': '#00ACED',
'DNS': '#DBDBDB',
'Finished': '#00BD07'
},
type : 'donut',
onclick: function (d, i) { console.log("onclick", d, i); }
// onmouseover: function (d, i) { console.log("onmouseover", d, i); },
// onmouseout: function (d, i) { console.log("onmouseout", d, i); }
},
donut: {
title: "Entrant Status",
label: {
format: function (value, ratio) {
return value;
}
}
}
});
};
display code :
<div class="row">
<div class="col-md-6">
{{> chart_cp_overview}}
</div>
<div class="col-md-6">
{{> chart_status}}
</div>
</div>
This code above displays only the last chart - chart_status. If I remove any one of the handlebars reference the other chart displays fine, or if I have multiple handlebars to multiple charts whatever was last declared is displayed.
How can I get multiple charts to display within one page? Example is on github at https://github.com/FickleLife/meteor-c3-test
It looks like maybe you are intending the two variable names you have chosen in your template rendered functions, cpOverview and chart, to bind to the dom elements with those ids. It won't work that way.
The variable names you have chosen are local to their functions and in any case would not automatically attach to elements with that id even if they were global. So c3 is binding all these charts to the same dom element (the docs say the default is #chart), and the last one is overriding the prior ones.
You want to bind each chart to its respective element. You can use this.firstNode inside your rendered function (based on the way you have it set up), or use jquery, or this.find("div#cpOverview"), and then use the c3 api to bind the chart to it - it looks like { bindto: "div#cpOverview" } may be the one you want.

Hide Parent's sbling ui-view quadrant when in a child state

When I go to a child state, I want to hide a ui-view component of a quadrant ui-view in root state. How can achieve this.
##index.html
<div ui-view="a">
</div>
<div ui-view="b">
</div>
<div ui-view="c">
</div>
##b.html
<div ui-view>
</div>
##config
$stateProvider.state('start', {
'views': {
'a': {
templateUrl: ...
},
'b': {
templateUrl: 'b.html'
},
'c': {
templateUrl: ...
}
},
controller: 'indexController
}).state('start.all', {
templateUrl: 'd.html',
controller: 'allController'
});
So when I reach start.all, I would like that the ui-view tagged c vanishes. How can I accomplish this.
There is an example demonstrating approach discussed below. The native way of ui-router, I'd say, is to manage all the views from current (active) state. We can do it with :
View Names - Relative vs. Absolute Names
... Behind the scenes, every view gets assigned an absolute name that follows a scheme of viewname#statename, where viewname is the name used in the view directive and state name is the state's absolute name, e.g. contact.item
In our case, the full name of the view 'c' would be c#, i.e. c as view name, # as delimiter and empty string representing the root (a bit weird but in fact logical).
Having that we can change the start.all definition like this:
.state('start.all', {
url : '/all',
'views': {
'': {
template: '<span>this is start ALL</span>',
},
'c#': {
template: '<span></span>',
},
},
})
And we will change the content of the c view in the root. And that should be the most native way with ui-router. It does not effectively remove it, but we can replace it with some empty stuff.
Also, into your example above, I placed controller called bController as contra example to the indexController:
.state('start', {
url : '/start',
'views': {
'a': {
template: ...
},
'b': {
template: ...
// HERE a new controller bController
controller: 'bController',
},
'c': {
template: ...
}
},
// the orginal contoller
controller: 'indexController',
})
and also defined them this way:
.controller('indexController', function($scope, $state, $stateParams) {
console.log('indexConroller was invoked');
})
.controller('bController', function($scope, $state, $stateParams) {
console.log('bConroller was invoked');
})
Why? to show you, that indexController will never be invoked. Contollers belongs to templates/views not to state...
Check all that together here
You could do it in a few ways. One way would be to have an abstract state containing views a and b. That abstract state then has two concrete child states: start, which adds view c, and all, which adds view d.
Another option is to just use the ng-show directive on the c view's root element bound to some scope variable. I would go with the first option.
Notably this does not answer the question because all is no longer a child of start. If there is a real need for all to inherit from start (there appears to be no need at present) you can just make start abstract and create a start.main and start.all.
Though Radim's solution is very clever and much appreciated, I think this is much more readable and intuitive than overriding a parent view with an empty template.
<body>
<div ng-app="myApp">
<a ui-sref="start.main">start</a> | <a ui-sref="start.all">all</a>
<hr />
<div class="rootView" ui-view="a"></div>
<div class="rootView" ui-view="b"></div>
<div class="rootView" ui-view=""></div>
</div>
<script>
var myApp = angular.module('myApp', ['ui.router']);
myApp.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/start/main');
$stateProvider
// Content common to all views
.state('shell', {
abstract: true,
views: {
"a": { template: '<div>View a here.</div>' },
"b": { template: '<div>View b here.</div>' },
"": { template: '<div ui-view></div>' }
}
})
// Content common to all 'start' views (currently nothing)
.state('start', {
parent: 'shell',
url: '/start',
abstract: true,
template: '<div ui-view></div>'
})
.state('start.main', {
url: '/main',
template: '<div>View c is here</div>'
})
.state('start.all', {
url: '/all',
template: '<div>View d is here</div>'
});
});
</script>
</body>

Reference to button by name

i am have 2 forms, and in first form i am have button1:
Buttons[{
width: 350,
text: 'Book',
name:'button1'}]
on second form i am have button2, and when button click in second form, then button in first form disabled, before i am use id of button (id:'button1') and make this:
Ext.getCmp('button1').setDisabled(true);
but now i am remove ID and use name in components. But i am didn"t know how disable button1 by name!
Buttons don't have a name property - you should consult the documentation to see what configuration variables you have available to you. I'd instead assign it an itemId so you can make use of the up() and down() functions in order to easily find an item in the component hierarchy from an event handler.
Or if you want to find it directly you can use the following to lookup up the item:
{
text : 'Button',
itemId : 'buttonSelector'
}
var button = Ext.ComponentQuery.query('#buttonSelector');
if(button.length) button[0].disable();
Keep in mind that the ComponentQuery utility returns an array of items (even if you make your itemId unique). Here's a simple fiddle / demonstration.
In response to your comment, there may be confusion in regards to what the buttons config actually does - according to the docs it is shorthand for the following:
dockedItems: [{
xtype: 'toolbar',
dock: 'bottom',
ui: 'footer',
defaults: {minWidth: minButtonWidth},
items: [
{ xtype: 'component', flex: 1 },
{ xtype: 'button', text: 'Button 1' }
]
}]
... this creates an extra "step" in the hierarchy which you must account for in a query. For example, if your form had an itemId of formId you could try something like:
Ext.ComponentQuery.query('#formId toolbar #myButtonId')[0].disable();
I've updated your fiddle to demonstrate this.

Resources