How can I add Ractive instances to a list? in a parent Ractive instance? - mvp

I already have a Ractive instance (or component - it could be either) and I want to add it to a list in another Ractive instance. Something like this:
var ListItemOne = new Ractive({
data: { key: "hello" }
});
var ListItemTwo = new Ractive({
data: { key: "world" }
});
var ractive = new Ractive({
el: "#output",
template: "#template",
data: { greeting: 'hi', name: 'there',
listItems: [
ListItemOne,
ListItemTwo
]
}
});
Template:
<p>{{greeting}} {{name}}!</p>
<ul>
{{#listItems}}
<li>{{key}}</li>
{{/listItems}}
</ul>
jsbin
Or using a method:
var ractive = new Ractive({
el: "#output",
template: "#template",
data: {
greeting: 'hi', name: 'there',
listItems: []
},
addListItem: function(listItem){
this.get('listItems').push(listItem);
}
});
ractive.addListItem(ListItemOne);
ractive.addListItem(ListItemTwo);
jsbin
Is it possible to use Ractive in this way?
Please note that I do not want this:
var ractive = new Ractive({
el: "#output",
template: "#template",
data: { greeting: 'hi', name: 'there',
listItems: [
{ key: "hello" },
{ key: "world" }
]
}
});
As I already have the Ractive instances/components, and I am using MVP to define explicitly define the interface between application and view.

The items in the list are ractive instances, so you have to call the get method to access their data if you want to use them that way (see http://jsbin.com/nomutofati/1/edit?html,js,output):
<ul>
{{#listItems}}
<li>{{this.get('key')}}</li>
{{/listItems}}
</ul>

Related

VueJs Props not read when setting initial value in data

I've been struggling a lot lately on how to set the initial value in local data property. I'm using Laravel with Vue.js
I have this code below in my component
props: {
user: '',
dates: {}
},
data() {
return {
bloodTypes: {},
bloodComponents: {},
data: {
order_date: this.dates.order_date,
order_details: []
},
}
},
I'm trying to get the value of the props 'dates' into the local variable.
order_date: this.dates.order_date
return undefined. Although you can see in the picture below that the props have been initialized.
I want to know how to get the props value into my local data
variables.
A little late to the party but I thought I would share my workaround when working with async data:
// in the parent component
<template>
<child :foo="bar" v-if="bar" />
</template>
Then you can safely follow the guide's recommended ways to initialize data value with props as so:
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}
Happy coding!
try this:
watch: {
dates: {
handler(val){
this.data.order_date = val.order_date;
},
deep: true
}
}
I finally solved this with, I have changed some variable name so that I won't be confused. It seems that you need to put props under watch in order to manipulate it.
props: [ 'user','blood_components', 'blood_types', 'current_date'],
data() {
return {
list: {
order_date: '',
}
}
},
watch:{
current_date: function() {
let self = this
self.list.order_date = this.current_date
}
},
How about using computed instead?
props: [
'user',
'dates'
],
data() {
return {
bloodTypes: {},
bloodComponents: {}
}
},
computed: {
data: function() {
return {
order_date: this.dates.order_date,
order_details: [] <= should be changed to something dynamically changed object
}
}
}
The problem is your props are not declared correctly.
props: {
user: '', // <-- DON'T DO THIS
dates: {} // <-- DON'T DO THIS
}
When using the object syntax for props, each key is the prop name, and the value is either a data type (e.g., String, Number, etc.):
props: {
user: String,
dates: Object
}
...or an object initializer (which allows you to specify data type and default value) like this:
props: {
user: {
type: String,
default: ''
},
dates: {
type: Object,
default: () => ({})
}
},
demo
Assign the values in the created or mounted hook.
Example: https://github.com/jserra91/vuejs_wrapper_elements_and_unit_tests/blob/master/src/components/ae/components/ea-select/EaSelect.vue

Vue 2, Cannot reference Prop Object in template

Problem: Although from the Vue DevTools I am passing the prop correctly and the router-view component has access to the data that it needs and in the correct format, whenever I try to access any of the data properties from within the template I get Uncaught TypeError: Cannot read property 'name' of null. It's really confusing because from the DevTools everything is a valid object and the properties are not null.
App.js
const game = new Vue({
el: '#game',
data: function() {
return {
meta: null,
empire: null,
planets: null
};
},
created: () => {
axios.get('/api/game').then(function (response) {
game.meta = response.data.meta;
game.empire = response.data.empire;
game.planets = response.data.planets;
});
},
router // router is in separate file but nothing special
});
main.blade.php
<router-view :meta="meta" :empire="empire" :planets="planets"></router-view>
script section of my Component.vue file
export default {
data: function() {
return {
}
},
props: {
meta: {
type: Object
},
empire: {
type: Object
},
planets: {
type: Array
}
}
}
Any ideas? Thanks in advance.
Because of your data is async loading so when my Component.vue renders your data in parent component may not be there. So you need to check if your data is loaded. You can try this code:
{{ meta != null && meta.name }}
PS: Your created hook should be:
created() {
axios.get('/api/game').then((response) => {
this.game.meta = response.data.meta;
this.game.empire = response.data.empire;
this.game.planets = response.data.planets;
});
},
router-view is a component from view-router which can help render named views. You can not pass empire and planets to it as those are props of your component.
You have to have following kind of code to pass empire and planets to your component:
<my-component :meta="meta" :empire="empire" :planets="planets"></my-component>
You can see more details around this here.

canjs findOne deferred

I learned that instead of using model.findAll and write code in call back function of findAll we can achieve same by using new model.List({}).
E.g., jsfiddle --> http://jsfiddle.net/CRZXH/48/ .. in this jsfiddle example List implementation works but findOne fails.
var people = new Person.List({});
return can.Component({
tag: 'people',
template: initView,
scope: {
people: people
}
})
Above example works fine, initially people is assigned with empty object but after ajax call complete people variable is updated with list and view updates on its own.
How to achieve the same in case of findOne?
var person = PersonModel.findOne({});
can.Component({
tag: 'person',
template: initView,
scope: person
})
This fails....
I did work around as below :
var person;
PersonModel.findOne({},function(data){
person = data
});
can.Component({
tag: 'person',
template: initView,
scope: person
})
This works only if I add asyn=false in findeOne ajax call.
I got solution for this problem from http://webchat.freenode.net/ #daffl
Solution : http://jsfiddle.net/CRZXH/49/
can.Model.extend('Person', {
findOne: 'GET api/metadata',
getMetadata: function() {
var result = new Person();
Person.findOne().then(function(data) {
result.attr(data.attr(), true);
});
return result;
}
}, {});
// Person component which uses findOne
can.Component({
tag: 'person',
scope: function() {
return {
person: Person.getMetadata()
}
}
})
1- the ID for findOne is mandatory
findOne({id: modelId})
2- You can put the person model in a viewmodel (AKA component scope) and not passe the value use can.stache plugin and can.map.define plugin for this
can.fixture({
"GET api/people":function(){
return [
{id: 1, name: "Person 1"},
{id: 2, name: "Person 2"}
];
},"GET api/people/{id}":function(request,response){
return {id: request.data.id, name: "Person "+request.data.id}
}
});
can.Model.extend('Person',{
findAll: 'GET api/people',
findOne: 'GET api/people/{id}',
},{});
can.Component.extend({
tag:'x-person',
scope:{
define:{
person:{
get:function(currentPerson,setFn){
Person.findOne({id: 2}, setFn);
}
}
}
}
});
var frag=can.view('personTmpl',{});
$('#main').html(frag);
Here is the fiddle http://jsfiddle.net/cherif_b/egq85zva/

Ace editor: how to have multiple tokens

I'm trying to create a mode using this two rules:
{
token: 'title',
regex: /#.*/
},
{
token: 'name',
regex: /#\w+/
}
Hovewer, the name rule will not have any effect in this example:
# Title with #name
Is there a way to make both rules work?
The first rule consumes the whole line and doesn't allow the second one to apply. For it to work, you need to create a nested state after the #
define(function(require, exports, module) {
"use strict";
var oop = require("../lib/oop");
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
var HighlightRules = function() {
this.$rules = {
start : [ {
token: 'comment',
regex: /#(?=.)/,
next: [{
token: 'empty',
regex: /$|^/,
next: "start"
},{
token: 'keyword',
regex: /#\w+/
},{
defaultToken : "comment"
}]
}]
};
this.normalizeRules();
};
oop.inherits(HighlightRules, TextHighlightRules);
exports.HighlightRules = HighlightRules;
});

Updating Child Panels in Sencha Touch MVC App

Developing a Sencha Touch MVC app that pulls data from json store (thats set up to a DB pulling out content from a Wordpress Blog).
Everything works up until my "detail" panel. Instead of it listening to the TPL, its just dumping some data. The data looks similar to my blog post, but is filled with other code and doesn't make much sense.
Here is a lean version of my list:
myApp.views.PostListView = Ext.extend(Ext.Panel, {
postStore: Ext.emptyFn,
postList: Ext.emptyFn,
id:'postlistview',
layout: 'card',
initComponent: function () {
/* this.newButton = new Ext.Button({
text: 'New',
ui: 'action',
handler: this.onNewNote,
scope: this
});*/
this.topToolbar = new Ext.Toolbar({
title: 'All Posts',
/* items: [
{ xtype: 'spacer' },
this.newButton
],*/
});
this.dockedItems = [ this.topToolbar ];
this.postList = new Ext.List({
store: myApp.stores.postStore,
grouped: true,
emptyText: '<div style="margin:5px;">No notes cached.</div>',
onItemDisclosure: true,
itemTpl: '<div class="list-item-title">{title}</div>' +
'<div class="list-item-narrative"><small>{body}</small></div>',
});
this.postList.on('disclose', function (record) {
this.onViewPost(record);
}, this),
this.items = [this.postList];
myApp.views.PostListView.superclass.initComponent.call(this);
},
onViewPost: function (record) {
Ext.dispatch({
controller: myApp.controllers.masterController,
action: 'viewpost',
post: record
});
},
});
And here is the "detail" view that is called on disclosure:
myApp.views.PostSingleView = Ext.extend(Ext.Panel, {
title:'Single Post',
id:'postsingleview',
layout:'card',
style:'background:grey;',
initComponent: function () {
this.new1Button = new Ext.Button({
text: 'Back',
ui: 'back',
handler: this.onViewList,
scope: this,
dock:"left"
});
this.top1Toolbar = new Ext.Toolbar({
items: [
this.new1Button
],
title: 'Single Posts',
});
this.postSinglePanel = new Ext.Panel({
layout:'fit',
flex:1,
scroll: 'vertical',
style:'padding:10px;background:yellow;',
itemTpl: '<tpl for=".">' +
'<div class="list-item-narrative">{body}</div>' +
'</tpl>',
});
this.dockedItems = [ this.top1Toolbar, this.postSinglePanel ];
myApp.views.PostSingleView.superclass.initComponent.call(this);
},
onViewList: function () {
Ext.dispatch({
controller: myApp.controllers.masterController,
action: 'viewlist',
});
},
});
And here is the controller that its talking to:
Ext.regController('masterController', {
'index': function (options) {
if (!myApp.views.mainView) {
myApp.views.mainView = new myApp.views.MainView();
}
myApp.views.mainView.setActiveItem(
myApp.views.postView
);
},
'viewpost': function (options) {
myApp.views.postSingleView.postSinglePanel.update(options.post);
myApp.views.postView.setActiveItem(
myApp.views.postSingleView,
{ type: 'slide', direction: 'left' }
);
},
});
myApp.controllers.masterController = Ext.ControllerManager.get('masterController');
When the data comes out, it looks similar to this:
http://i.imgur.com/QlQG8.png
(the black boxes are "redacted" content, no error code there).
In closing, I believe that the controller is "dumping" the data into "MyApp.views.PostSingleView" rather than formatting it as I request in the TPL, though I'm not sure how to fix it. Any and all help MUCH appreciated!
UPDATE: As requested, here is the RegModel:
Ext.regModel("CategoryModel", {
fields: [
{name: "id", type: "int"},
{name: "title", type: "string"},
{name: "body", type: "string"},
],
hasMany: {
model: 'Post',
name: 'posts'
}
});
And here is a sample of the json:
{
   "status":"ok",
   "post":{
      "id":1037,
      "type":"post",
      "slug":"post-title",
      "url":"http:\/\/localhost:8888\/jsontest\/PostTitle\/",
      "status":"publish",
      "title":"Post Title",
      "title_plain":"Post Title",
      "content":"<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.<br \/>\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.<\/p>\n<!-- PHP 5.x -->",
      "excerpt":"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat [...]",
      "date":"2011-07-29 14:17:31",
      "modified":"2011-08-30 01:33:20",
      "categories":[
         {
            "id":87,
            "slug":"the-category",
            "title":"The Category",
            "description":"",
            "parent":17,
            "post_count":5
         }
      ],
      "tags":[
      ],
      "author":{
         "id":2,
         "slug":"tom",
         "name":"tom",
         "first_name":"tom",
         "last_name":"",
         "nickname":"",
         "url":"",
         "description":""
      },
      "comments":[
      ],
      "attachments":[
      ],
      "comment_count":0,
      "comment_status":"open"
   },
   "previous_url":"http:\/\/localhost:8888\/jsontest\/next-post\/",
   "next_url":"http:\/\/localhost:8888\/jsontest\/prev-post\/"
}
Use the tpl config option of the Ext.Panel not the itemTpl which doesn't exist.
As someone has mentioned before, be careful when using a Model instance and the update method, you will need to use the model's data property.
Try using this:
myApp.views.postSingleView.postSinglePanel.update(options.post.data);
the reason is that post does not actually expose the underlying data directly, you need to use the property data for that.
Also any particular reason why you are docking the postSinglePanel? I would be very careful using too many docked items as they are a known source of bugs and layout issues.
A simple way is to write your own method to update child panels (you can also see to override the default update method)
myApp.views.PostSingleView = Ext.extend(Ext.Panel, {
initComponent: function () {
// [...]
},
// [...]
myUpdate: function(data) {
this.postSinglePanel.update(data);
this.doComponentLayout(); // not sure if necessary...
}
});
and from your controller:
Ext.regController('masterController', {
// [...]
'viewpost': function (options) {
myApp.views.postSingleView.myUpdate(options.post.data); // note the .data
// [...]
},
});

Resources