Angularjs - ng-repeat and nested scope - angularjs-ng-repeat

I'm new to angularjs and trying to grasp the concept of accessing data in a nested scope.
Here is the main scope "company" containing a nested scope of objects "contacts":
$scope.company =
{
companyName: "",
contacts: {
name: "",
email: ""
}
}
I'm trying to generate a table with the data from "contacts" scope in each row.
<tr ng-repeat="contact in company.contacts">
<td>
<input type="text" class="form-control" ng-model="contact.name"/>
</td>
<td>
<input type="text" class="form-control" ng-model="contact.email"/>
</td>
</tr>
But it seems that I'm doing something wrong here, as when I try to display the data from the main scope {{company}} nothing really happens.
I could really use some advice. Thank you.

You don't want to use a loop for this.
Just use company.contacts.name and company.contacts.email.
However I suspect you might want to have multiple contacts, hence the plural contacts. For that you need to make contacts an array.
With an array you can use the repeat.
Like this:
$scope.company =
{
companyName: "",
contacts: [
{
name: "",
email: ""
},
{
name: "",
email: ""
}
]
}
Off topic: If you're just learning Angular1 and don't already have a massive project you're working on, switch to Angular2+ (currently 6). AngularJs (1.x) is a framework that's just on long term support for another year and a half. (AngularJs (1.x) and Angular (>= 2 ) are different frameworks.)

Related

Mailchimp API and mc:repeatable

I'm working with the MailChimp Transactional API but am having an issue populating an email template that uses a mc:repeatable section. I can't find any docs or examples on how to do this. Here is the endpoint im using https://mailchimp.com/developer/transactional/api/messages/send-using-message-template/
And here is my email template
<!DOCTYPE html>
<html lang="en">
<head>
<title>Your Order</title>
</head>
<body>
<div>Thanks for your order</div>
<div>Your receipt for your order from</div>
<div mc:edit="store_name">Store Name</div>
<div>Order Type</div>
<div mc:edit="order_type">Type</div>
<div>Products:</div>
<table>
<tr mc:repeatable="products">
<td mc:edit="quantity">Quantity</td>
<td mc:edit="product_name">Product Name</td>
<td mc:edit="price">Price</td>
</tr>
</table>
</body>
</html>
I'm able to populate all of the mc:edit areas using this as the template_content in the request body:
const content = [
{
name: 'store_name',
content: 'Any Store Name'
},
{
name: 'order_type',
content: 'Pickup Order'
},
{
name: 'subtotal',
content: '$80.00'
},
{
name: 'taxes',
content: '$2.22'
},
{
name: 'fees',
content: '$0.00'
},
{
name: 'total',
content: '$82.22'
}
]
I can even populate a SINGLE row in the repeatable section if I add objects for quantity, product_name and price but I need to be able to REPEAT this section and add multiple quantity > product name > price lines.
Any advice or help or docs would be great, thanks!
From the MailChimp template language reference, it doesn't appear that <tr> elements are supported by mc:repeatable. See the third (bolded) point and note that, while <table> is a block level element, <tr> is not.
mc:repeatable
mc:repeatable is used to provide a duplication action for a particular element within a template.
Syntax: mc:repeatable.
Use mc:repeatable on block-level elements (like <div> and <p>) with the exception of lists, or inline elements (like <img>, <a>, and <span>).
mc:repeatable elements can be nested within each other, but use care if you’re going to do this. We don’t encourage this use.
mc:repeatable can be used on the same element as mc:edit, but nesting mc:repeatable beneath mc:edit will render content that is editable but not repeatable.
If you want to apply styles to repeatable container elements or elements within repeatable containers, either use class or apply them in-line. Don’t use the id attribute.
If they do happen to work, you might need to use mc:variant and per-product names for the subfields. Something like this:
<table>
<tr mc:repeatable="products" mc:variant="product1">
<td mc:edit="product1_quantity">Quantity</td>
<td mc:edit="product1_product_name">Product Name</td>
<td mc:edit="product1_price">Price</td>
</tr>
<tr mc:repeatable="products" mc:variant="product2">
<td mc:edit="product2_quantity">Quantity</td>
<td mc:edit="product2_product_name">Product Name</td>
<td mc:edit="product2_price">Price</td>
</tr>
<tr mc:repeatable="products" mc:variant="product3">
<td mc:edit="product3_quantity">Quantity</td>
<td mc:edit="product3_product_name">Product Name</td>
<td mc:edit="product3_price">Price</td>
</tr>
</table>
const content = [
{
name: 'product1_quantity',
content: '5'
}, {
name: 'product1_name',
content: 'Some Product'
}, {
name: 'product1_price',
content: '$49.99'
},
{
name: 'product2_quantity',
content: '1'
}, {
name: 'product2_name',
content: 'Some Other Product'
}, {
name: 'product2_price',
content: '$1,200'
},
{
name: 'product3_quantity',
content: '13'
}, {
name: 'product3_name',
content: 'Some Third Product'
}, {
name: 'product3_price',
content: '$17.50'
}
];
If this looks like it isn't for building a list from dynamic data, that's because I don't think it is. It looks like it's a tool for easily getting styles into the Campaign Builder.
Inside the builder, there is a Product concept that includes the kind of information you appear to want to send in your email. The tutorial for the builder indicates that while a Product section is repeatable, you need to have a source of data connected to the builder and must choose the Products to include at design time.
Use Product content blocks to add items from your connected online store. Each block is designed to contain a product name, custom description, price, and call-to-action button. And if you turn on e-commerce tracking in your email settings, your report will show purchase revenue.
To use a Product block, follow these steps.
Click a Product block or add one to your email. If you’re working with an existing block, skip to step 4.
In the Select a store modal, choose the store you want to add products from. If you haven’t yet connected a store, you’ll be prompted to do so.
Click the product you want to add.
In the Products menu, edit the Title, Button, and Link to URL as needed. You can also click the edit icon to choose a different product, or click the settings icon to check your store connection.

VueJs and Laravel - multiple select fields

Using Laravel 5.4 and Vuejs 2.1
In code I have a select field with two input fields (quantity and stock) in tr (Table Row). Table Row with the fields can be dynamically added as much as user is needed, this is the code:
<tbody id="loads-content">
<tr v-for="(item, index) in items">
<td>
<select v-model="item.load_id" name="load_id[]" class="loads" v-on:change="getLoadStock()">
<option v-for="load in loads" :value="load.id" :id="load.id">{{load.name}}</option>
</select>
</td>
<td><input type="text" v-model="item.quantity" name="quantity[]" class="input is-hovered qty"></td>
<td><input type="text" v-model="item.stock" class="input is-hovered stock" disabled readonly="true"></td>
<td>
<button type="button" class="button is-danger remove" #click="items.splice(index, 1)"><i class="fa fa-minus-square-o" aria-hidden="true"></i></button>
</td>
</tr>
<a #click="addLine" class="button is-success"><i class="fa fa-plus-square-o" aria-hidden="true"></i></a>
</tbody>
When you choose some value from select field I need to populate the STOCK input field with stock data from the database. For that I used an API call. I made something like this:
methods: {
addLine() {
this.items.push({
load_id: '',
quantity: '',
stock: ''
})
},
getLoadStock(){
var loadsContent = $('#loads-content');
var tr = loadsContent.parent().parent();
var id = tr.find('.loads').val();
axios.get('/api/load/' + id)
.then(function(response) {
tr.find('.stock').val(response.data.stock);
})
.catch(function(error) {
console.log(error)
});
},
This code is not working as expected.
The goal is to fetch actual stock for current choosen load, to see how much quantity can you enter in the input field for quantity.
I am open for any suggestions, if anyone has a better approach and solution please help.
Thanks in advance! :)
You are mixing two different and incompatible ways of building a web app: Vue.js and jQuery.
When using Vue, you should not be manipulating the DOM directly. You should instead be binding the DOM elements to Vue model attributes. Then, if you need a DOM element to reflect a change, you change the model – not the DOM.
So for instance, you would want something like this (note adding index as an argument to getLoadStock):
<select v-model="item.load_id" name="load_id[]" class="loads" v-on:change="getLoadStock(index)">
<option v-for="load in loads" :value="load.id" :id="load.id">{{load.name}}</option>
</select>
and
getLoadStock(index){
axios.get('/api/load/' + this.items[index].load_id)
.then(function(response) {
this.items[index].stock = response.data.stock;
})
.catch(function(error) {
console.log(error)
});
},

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/

How to prepopulate tokenput with values found in database

I am using the tokeninput control found here at http://loopj.com/jquery-tokeninput/ - its quite popular I believe.
I have the following code that fills the input box nicely with author names - but I want to prepopulate the control with values found in the database when the user is in an EDIT session i.e. to find authors that have been found for that record already (looks something like this):
Here's the code:
$("#authorlist").tokenInput('/author/getauthors/', {
hintText: "Enter surname",
searchingText: "Searching...",
preventDuplicates: true,
allowCustomEntry: true,
highlightDuplicates: false,
tokenDelimiter: "*",
theme: "facebook"
// prePopulate: [{"id": 5016, "name": "Test 1" }]
});
Obviously this already gets a full list of authors (/author/getauthors/) - but it needs to prepopulate from that list too, with authors already found that record - and thats the bit I can't seem to figure out.
I can see that that you can use prePopulate in the javascript (I've commented it out) and I have the found author values in my Edit.cshtml i.e.
#foreach(var item in Model.AUTHORs.Select(model => new { model} ))
{
<div type="hidden" id="authorHidden" > #item.model.FULL_NAME</div>
}
So it's just a case of putting those values in some kind of json format and getting the tokeninput control to populate them ready for when the form is loaded and shown to the user.
Other code for displaying the tokeninput control in Edit.cshtml is:
<div class="editor-label">Authors</div>
<div class="authors">
<div class="editor-field">
<input type="text" id="authorlist" name="tiAuthors" />
</div>
</div>
Any help or pointers are much appreciated.
You could use an HTML5 data-* attribute on your input inside the view to put the list of authors that you want to be prepopulated:
<input type="text" id="authorlist" name="tiAuthors" data-authors="#Json.Encode(Model.AUTHORs.Select(a => new { id = a.AuthorId, name = a.AuthorName })))" />
and then:
$('#authorlist').tokenInput('/author/getauthors/', {
hintText: 'Enter surname',
searchingText: 'Searching...',
preventDuplicates: true,
allowCustomEntry: true,
highlightDuplicates: false,
tokenDelimiter: '*',
theme: 'facebook',
prePopulate: $('#authorlist').data('authors')
});

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