canjs model not populating mustache template - canjs

I am very new to CanJs just started learning, I am struck with below problem not able to debug it.
I have model as below:
Localized = can.Model({
findOne : 'GET /resources/localized'
}, {
});
GET /resources/localized ---> fetches available localized languages.
And I have defined a component as below
can.Component({
tag : 'preferences',
template : initView,
init: function() {
console.log(locales);
},
scope : {
locales: new LocalizedModel.findOne({})
}
});
initView has mustache template as below:
<div class="form-group">
<label>{{dateLayout}}</label>
<select class="form-control" id="lang" name="lang" can-change="save">
{{#list locales.languageOptions}}
<option value="{{name}}">{{name}}</option>
{{/list}}
</select>
</div>
But the problem is locales are not getting populate, I could see network call for /resources/localized, any pointers here could really help to understand this.

Be careful to use the correct naming, especially if you were reading up on both EJS and Mustache building from the CanJS documentation. The helper that iterates over a list is {{#each listref}}...{{/each}} in can.Mustache and can.Stache, where in can.EJS it is <% list(listref, function(item) { %>...<% }) %>. Using {{#list ...}} will likely not produce anything.

Related

2 way binding with Vue3 Inline template (using slots) in laravel blade template files

In Vue3, inline-templates were depreciated and now slots are used. Is it possible to have 2-way binding of variables for Vuejs components written in blade templates?
I want to have 2-way binding for Vue components that's written inline with blade templates. Although I know I can pass data like <example-component name="Hello World"> It is a ton of work to add props everywhere.
Vue recommends using slots as a inline-template replacement since it got removed in v3, however, that documentation makes no sense. I've got the components displayed using the code below. It's a dead simple text field + paragraph to display the name.
home.blade.php (Removed unnecessary HTML for brevity)
<div>
<h1>Dashboard</h1>
<example-component>
<div class="container">
<input v-model="name" placeholder="Change Name"/>
<p> Name is #{{ name }} </p>
</div>
</example-component>
</div>
example-component.vue
<template>
<div>
<slot></slot>
</div>
</template>
<script>
export default {
data() {
return {
name: 'hi',
}
}
}
</script>
Unfortunately, this does not work, the name doesn't start as 'hi' and doesn't update when changing the textfield. When I try something like <slot :name=name></slot>. Which I believe would pass the name into the slots section, the component gets rendered for a second before disappearing.
Is having 2-way binding with vue variables in blade templates even possible? Any help is appreciated.
Vue: 3.0.5
Laravel: 8.29.0
Is there a reason you're storing the data in the child component? The reactivity design works by passing props down and emitting events up, even though (unfortunately) the reactivity is not maintained when passing a variable up to the parent component. Seems a little counter intuitive, but I might be missing something in what you're trying to create.
It will, however, work if you put the data into the app instead of the component.
// app
const app = Vue.createApp({
data() {
return {
name: 'hi',
}
}
})
// component
app.component('example-component', {
template: `
<div>
<slot></slot>
</div>`,
})
app.mount("#app");
<script src="https://unpkg.com/vue#3.0.5/dist/vue.global.prod.js"></script>
<div id="app">
<h1>Dashboard</h1>
<example-component>
<div class="container">
<input v-model="name" placeholder="Change Name"/>
<p> Name is #{{ name }} </p>
</div>
</example-component>
</div>
<!--

BigCommerce - showing product SKU inside the option label

I'm editing a custom theme in BigCommerce, and I'm working on the product options section of the code on a product page. This is for a product page for a product with multiple options. A default parent SKU is shown above the options. Upon choosing an option, the new, final SKU gets populated above. The handlebar code to show that SKU is {{product.sku}}.
I've found that customers get confused and don't realize there are other SKUs available if they just choose the right option, so I want to show the SKU within the label of the option.
Here is the part of the code I'm targeting (from set-rectangle.html):
<div class="form-field" data-product-attribute="set-rectangle">
<label class="form-label form-label--alternate form-label--inlineSmall">
{{this.display_name}}:
<span data-option-value></span>
{{#if required}}
<small>{{lang 'common.required'}}</small>
{{/if}}
</label>
{{#each this.values}}
<input
class="form-radio"
type="radio"
id="attribute_rectangle__{{../id}}_{{id}}"
name="attribute[{{../id}}]"
value="{{id}}"
{{#if selected}}
checked
data-default
{{/if}}
{{#if ../required}}required{{/if}}>
<label class="form-option" for="attribute_rectangle__{{../id}}_{{id}}" data-product-attribute-value="{{id}}">
<span class="form-option-variant">{{this.label}}<br>{{product.sku}}</span>
</label>
{{/each}}
</div>
I've tried inserting {{product.sku}} inside the label - as you can see above, but that doesn't work - nothing populates. I think it needs to reference the option with a "this" in there somewhere, but that's the extent of my coding savviness.
A single product attribute does not necessarily determine the variant, as there may be more attibutes, a combination of which would determine a specific variant (e.g. "Size" and "Color" Vs. just "Size").
That said, when (and only when) you have variants defined by a single product attribute (e.g. "Size"), you could actually bind a specific SKU to each of the attribute values (e.g. "30ml" => sku "AAA", "50ml" => sku "BBB").
I'm afraid the variant SKUs are not included in the data available as part of the "values", for the reasons above.
In fact, if you add the "debug" line (useful sometimes) using the "json" helper:
{{#each this.values}}
<input
class="form-radio"
type="radio"
id="attribute_rectangle__{{../id}}_{{id}}"
name="attribute[{{../id}}]"
value="{{id}}"
{{#if selected}}
checked
data-default
{{/if}}
{{#if ../required}}required{{/if}}>
<label class="form-option" for="attribute_rectangle__{{../id}}_{{id}}" data-product-attribute-value="{{id}}">
<span class="form-option-variant">{{this.label}}</span>
</label>
<!-- {{{json this}}} -->
{{/each}}
(note "json this"), you will see that the HTML produced only includes, for each variant, the "label", "id" (variant ID), "data", and "selected" properties, no variant SKU in there...
<!-- {"label":"30ml","id":104,"data":"30ml","selected":false} -->
If you can identify the product variant ID (the above is the option value ID, not a variant ID), you can retrieve the missing data using the BigCommerce Store Front API (specifically GraphQL) and JavaScript, and then use that data to inject SKUs in your HTML, see the following example from BigCommerce:
https://developer.bigcommerce.com/api-docs/storefront/graphql/graphql-storefront-api-samples#get-variant-details-as-a-product-object
That JavaScript would look something like this:
<script>
(function(w) {
const sfApiToken = '{{json settings.storefront_api.token}}';
if (sfApiToken) {
w.document.querySelectorAll('[data-vidsku]').forEach((e) => {
const vid = e.getAttribute('data-vidsku') || null;
if (vid) {
const queryS = `query VariantById {
site {
product(variantEntityId: ${vid}}) {
sku
}
}
}`;
fetch('/graphql', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${sfApiToken}`
},
body: JSON.stringify({query: queryS})
})
.then((res) => res.json())
.then((json) => {
e.textContent = json.product.sku || '';
});
}
});
}
})(window);
</script>

Vuejs tags and ajax

Hello
i am coding a web page of posts, where I'd like to add a tag system, something like stack overflow.
I have found many useful codes already made like Tag it by: aehlke.
The problem it´s that i want to use almost all the code by vuejs.org.
I am at laravel 5.3 framework and vuejs also using jquery.
Coul you please help me with the js to make a "separated by comma" tag that only can use the tags already in Tags table.
i used the example in vuejs.org to make made a searchbox that searches at a vue var and displays it at the bottom, i tought i coul use laravel variables to make the vuejs var and then search, but how could i make that each time a value its clicked on the table at bottom, the text fields updates with a tag inside.
<script type="text/x-template" id="grid-template">
<table>
<tbody>
<tr v-for="
entry in data
| filterBy filterKey
| orderBy sortKey sortOrders[sortKey]">
<td v-for="key in columns">
{{entry[key]}}
</td>
</tr>
</tbody>
</table>
</script>
<div id="demo">
<form id="search">
Search <input name="query" v-model="searchQuery">
</form>
<demo-grid
:data="gridData"
:columns="gridColumns"
:filter-key="searchQuery">
</demo-grid>
</div>
Vue.component('demo-grid', {
template: '#grid-template',
props: {
data: Array,
columns: Array,
filterKey: String
},
methods: {
sortBy: function (key) {
this.sortKey = key
this.sortOrders[key] = this.sortOrders[key] * -1
}
}
})
// bootstrap the demo
var demo = new Vue({
el: '#demo',
data: {
searchQuery: '',
gridColumns: ['tag'],
gridData: [
{ tag: 'Movies'},
{ tag: 'Tv Shows' },
{ tag: 'Books'},
{ tag: 'Comics' }
]
}
})
Help.
This isn't a "code-this-for-me"-site so if you want some help you need to post some code and someone might tell you what's wrong with it.
Anyhow, one of these JS libraries might be of interest to you:
https://select2.github.io/
http://selectize.github.io/selectize.js/

angularjs $scope.$apply() doesnt update select list on ajax IE9

So to keep it simple, im trying to update my select list with a new list of items that i get from an ajax-call. The list has the items. I set the model to the new list and do a $scope.$apply(). This works great in firefox, but not in IE. What am I doing wrong? Is there some IE9-thing that I'm missing? (I've been looking for a few hours now and am ready to give up). Appreciate all the help I can get.
HTML:
<select
ng-model="SelectedParameter"
ng-options="Parameter.Name for Parameter in AllParameters">
</select>
JS:
$.getJSON("/Cont/GetList", {id: id},
function (result) {
var allParameters = result.Data.AllParameters;
$scope.AllParameters = allParameters;
$scope.$apply();
}
);
You'd be way better off doing this the "Angular way". No JQuery required! In fact, if you find yourself doing things the "JQuery way" you're probably doing it wrong. Mark Rajcok had a really good question (and answer) about this same thing on StackOverflow a while ago:
app.js
//declare your application module.
var app = angular.module('myApp', []);
//declare a controller
app.controller('MainCtrl', function($scope, $http) {
//function to update the list
$scope.updateList = function () {
$http.get('/Cont/GetList', function(data) {
$scope.allParameters = data;
});
};
//initial load
$scope.updateList();
});
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script src="angular.js"></script>
<script src="app.js"></script>
</head>
<body>
<div ng-controller="MainCtrl">
<button ng-click="updateList()">Update</button>
<ul>
<li ng-repeat="parameter in allParameters">{{parameter | json}}</li>
</ul>
<!-- EDIT: Because you requested a select.
or if you wanted to do a select list
assuming every object in your array had a "name" property
you wanted to display in the option text, you could do
something like the following:
(NOTE: ng-model is required for ng-options to work)
-->
<select ng-model="selectedValue" ng-options="p as p.name for p in allParameters"></select>
<!-- this is just to display the value you've selected -->
<p>Selected:</p>
<pre>{{selectedValue | json}}</pre>
</div>
</body>
</html>
EDIT: A common problem in IE
So first of all, if you're having a problem in IE, I'd recommend hitting F12 and seeing what errors you're getting in the console.
The most common issue I've seen that breaks things in IE relate to commands such as console.log() which don't exist in IE. If that's the case, you'll need to create a stub, like so:
//stub in console.log for IE.
console = console || {};
console.log = console.log || function () {};
I think it's an IE issue. Try setting display:none before you update, then remove the display setting after you update.
I believe it is this bug that is ultimately the problem. I've been pulling my hair out for a couple of days on something very similar, a select filtered off of another.
At the end of the day OPTIONS are being added dynamically and IE9 just chokes on it.
<div class="col-lg-2">
<div class="form-group">
<label>State</label>
<select data-ng-model="orderFilter.selectedState"
data-ng-options="s.StateAbbr for s in states"
data-placeholder="choose a state…"
class="form-control">
<option value=""></option>
</select>
</div>
</div>
<div class="col-lg-2">
<div class="form-group">
<label>County</label>
<select data-ng-model="orderFilter.selectedCounty"
data-ng-options="c.CountyName for c in filteredCounties | orderBy:'CountyName'"
data-ng-disabled="orderFilter.selectedState == null"
data-placeholder="Choose a county…"
class="form-control">
<option value=""></option>
</select>
</div>
</div>
Regards,
Stephen

knockout with dynamic viewmodels

There's a ton of info on the interwebs about how to handle dynamic views (via ajax calls) with Knockout, but is there a best practice for dynamic viewmodels?
For instance, say I have a single page app that renders (via ajax) different types of forms (with different input fields) based on role, user choices, contexts, etc. Not only would I use templates for each form, but I'd like to do the same for the viewmodel, since each viewmodel may have many very different properties and it wouldn't be practical to have one massive viewmodel for every possible template.
I'm a bit of a rookie with ko, and it may not be meant to be used in this fashion. Any advice is much appreciated.
A popular way to do this type of thing is to have a main view model that hosts sub-view models.
Here is a really basic example of defining "model" objects that have a template and associated data.
function Model(key, template, data) {
this.key = key;
this.template = ko.observable(template);
this.data = data;
}
var viewModel = {
models: ko.observableArray([
new Model("user", "userTmpl", { first: "Bob", last: "Smith" }),
new Model("item", "itemTmpl", { name: "MyItem", description: "Here are some details" })
]),
selectedModel: ko.observable()
};
ko.applyBindings(viewModel);
Then, you could use it like:
<select data-bind="options: models, optionsText: 'key', optionsCaption: 'select a model...', value: selectedModel"></select>
<hr />
<div data-bind="with: selectedModel">
<div data-bind="template: { name: template(), data: data }"></div>
</div>
<script id="userTmpl" type="text/html">
<span data-bind="text: last"></span>, <span data-bind="text: first"></span>
</script>
<script id="itemTmpl" type="text/html">
<h3 data-bind="text: name"></h3>
<div data-bind="text: description"></div>
</script>
http://jsfiddle.net/rniemeyer/29kWf/
Obviously, you wouldn't likely bind the selection of the model in a select, but it helps show how it can work. Rather than an array your models could be an object with the property names matching the key.
The "data" in the "model" objects would be your sub-view models.
I'm Facing the same problem.
Try Knockout Namespaces

Resources