How to use dynamic observable variable names in html files in knockoutjs - php

I am using knockjs and I have created dynamic observableArrays in js file.
Ex. product+productid which creates a dynamic observableArrays as product123.
I want to use this in a data bind foreach loop and want to create this variable dynamically again in html file.
Something like : data-bind="foreach: { data: "product"+product.id()()}
So this "product"+product.id()() binding should call my product123() array.
How can I achieve this?

Hey it worked with vm['product'+product.id()]

You can use $data to refer to the current context, and use array notation to index your dynamically-named element.
vm = {
product: ko.observable('123'),
product123: ko.observableArray([
'one', 'two', 'three'
])
};
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="foreach: $data['product'+product()]">
<div data-bind="text: $data"></div>
</div>

Related

Inject Blade Array into script using HTML data attribute

I have a blade template, which has a script included in it. That script needs access to language strings, which are accessible in a #lang('intro') variable. I am wondering if there is way of injecting the whole array into the script via a html data attribute, and then retrieve it in the script using jquery.
So far I have the following:
../en/intro.php:
<?php
return [
'step1' => 'Welcome',
'step2' => 'Step 2',
];
../de/intro.php
<?php
return [
'step1' => 'Willkommen',
'step2' => 'Schritt 2',
];
In the blade template I am injecting each string:
<script data-id="intro-script"
data-introStep1="#lang('intro.step1')"
data-introStep2="#lang('intro.step2')"
src="{{ mix('js/intro.js') }}">
And retrieve it using jQuery in the script intro.js:
document.querySelector('script[data-id="intro-script"]').getAttribute('data-introStep1');
This works so far, but isn't great for many more strings. I am wondering if its possible to combine data-introStep1 and data-introStep2 in a single data attribute which contains the whole #lang('intro') array, not just a single string per attribute.
Your translation file can be packed as JSON encoded string like so:
<script data-id="intro-script"
data-intro='#json(__('intro'))'
src="{{ mix('js/intro.js') }}"
></script>
Then, retrieve using Javascript.
const intro = JSON.parse(
document.querySelector('script[data-id="intro-script"]').dataset.intro
);

How to delete single field from the table in angularjs [duplicate]

I am trying to write a function that enables me to remove an item when the button is clicked but I think I am getting confused with the function - do I use $digest?
HTML & app.js:
<ul ng-repeat="bday in bdays">
<li>
<span ng-hide="editing" ng-click="editing = true">{{bday.name}} | {{bday.date}}</span>
<form ng-show="editing" ng-submit="editing = false">
<label>Name:</label>
<input type="text" ng-model="bday.name" placeholder="Name" ng-required/>
<label>Date:</label>
<input type="date" ng-model="bday.date" placeholder="Date" ng-required/>
<br/>
<button class="btn" type="submit">Save</button>
<a class="btn" ng-click="remove()">Delete</a>
</form>
</li>
</ul>
$scope.remove = function(){
$scope.newBirthday = $scope.$digest();
};
To remove item you need to remove it from array and can pass bday item to your remove function in markup. Then in controller look up the index of item and remove from array
<a class="btn" ng-click="remove(item)">Delete</a>
Then in controller:
$scope.remove = function(item) {
var index = $scope.bdays.indexOf(item);
$scope.bdays.splice(index, 1);
}
Angular will automatically detect the change to the bdays array and do the update of ng-repeat
DEMO: http://plnkr.co/edit/ZdShIA?p=preview
EDIT: If doing live updates with server would use a service you create using $resource to manage the array updates at same time it updates server
This is a correct answer:
<a class="btn" ng-click="remove($index)">Delete</a>
$scope.remove=function($index){
$scope.bdays.splice($index,1);
}
In #charlietfl's answer. I think it's wrong since you pass $index as paramter but you use the wish instead in controller. Correct me if I'm wrong :)
In case you're inside an ng-repeat
you could use a one liner option
<div ng-repeat="key in keywords">
<button ng-click="keywords.splice($index, 1)">
{{key.name}}
</button>
</div>
$index is used by angular to show current index of the array inside ng-repeat
Using $index works perfectly well in basic cases, and #charlietfl's answer is great. But sometimes, $index isn't enough.
Imagine you have a single array, which you're presenting in two different ng-repeat's. One of those ng-repeat's is filtered for objects that have a truthy property, and the other is filtered for a falsy property. Two different filtered arrays are being presented, which derive from a single original array. (Or, if it helps to visualize: perhaps you have a single array of people, and you want one ng-repeat for the women in that array, and another for the men in that same array.) Your goal: delete reliably from the original array, using information from the members of the filtered arrays.
In each of those filtered arrays, $index won't be the index of the item within the original array. It'll be the index in the filtered sub-array. So, you won't be able to tell the person's index in the original people array, you'll only know the $index from the women or men sub-array. Try to delete using that, and you'll have items disappearing from everywhere except where you wanted. What to do?
If you're lucky enough be using a data model includes a unique identifier for each object, then use that instead of $index, to find the object and splice it out of the main array. (Use my example below, but with that unique identifier.) But if you're not so lucky?
Angular actually augments each item in an ng-repeated array (in the main, original array) with a unique property called $$hashKey. You can search the original array for a match on the $$hashKey of the item you want to delete, and get rid of it that way.
Note that $$hashKey is an implementation detail, not included in the published API for ng-repeat. They could remove support for that property at any time. But probably not. :-)
$scope.deleteFilteredItem = function(hashKey, sourceArray){
angular.forEach(sourceArray, function(obj, index){
// sourceArray is a reference to the original array passed to ng-repeat,
// rather than the filtered version.
// 1. compare the target object's hashKey to the current member of the iterable:
if (obj.$$hashKey === hashKey) {
// remove the matching item from the array
sourceArray.splice(index, 1);
// and exit the loop right away
return;
};
});
}
Invoke with:
ng-click="deleteFilteredItem(item.$$hashKey, refToSourceArray)"
EDIT: Using a function like this, which keys on the $$hashKey instead of a model-specific property name, also has the significant added advantage of making this function reusable across different models and contexts. Provide it with your array reference, and your item reference, and it should just work.
I usually write in such style :
<a class="btn" ng-click="remove($index)">Delete</a>
$scope.remove = function(index){
$scope.[yourArray].splice(index, 1)
};
Hope this will help
You have to use a dot(.) between $scope and [yourArray]
Building on the accepted answer, this will work with ngRepeat, filterand handle expections better:
Controller:
vm.remove = function(item, array) {
var index = array.indexOf(item);
if(index>=0)
array.splice(index, 1);
}
View:
ng-click="vm.remove(item,$scope.bdays)"
implementation Without a Controller.
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>
<script>
var app = angular.module("myShoppingList", []);
</script>
<div ng-app="myShoppingList" ng-init="products = ['Milk','Bread','Cheese']">
<ul>
<li ng-repeat="x in products track by $index">{{x}}
<span ng-click="products.splice($index,1)">×</span>
</li>
</ul>
<input ng-model="addItem">
<button ng-click="products.push(addItem)">Add</button>
</div>
<p>Click the little x to remove an item from the shopping list.</p>
</body>
</html>
The splice() method adds/removes items to/from an array.
array.splice(index, howmanyitem(s), item_1, ....., item_n)
index:
Required. An integer that specifies at what position to add/remove items, Use negative values to specify the position from the end of the array.
howmanyitem(s): Optional. The number of items to be removed. If set to 0, no items will be removed.
item_1, ..., item_n: Optional. The new item(s) to be added to the array
I disagree that you should be calling a method on your controller. You should be using a service for any actual functionality, and you should be defining directives for any functionality for scalability and modularity, as well as assigning a click event which contains a call to the service which you inject into your directive.
So, for instance, on your HTML...
<a class="btn" ng-remove-birthday="$index">Delete</a>
Then, create a directive...
angular.module('myApp').directive('ngRemoveBirthday', ['myService', function(myService){
return function(scope, element, attrs){
angular.element(element.bind('click', function(){
myService.removeBirthday(scope.$eval(attrs.ngRemoveBirthday), scope);
};
};
}])
Then in your service...
angular.module('myApp').factory('myService', [function(){
return {
removeBirthday: function(birthdayIndex, scope){
scope.bdays.splice(birthdayIndex);
scope.$apply();
}
};
}]);
When you write your code properly like this, you will make it very easy to write future changes without having to restructure your code. It's organized properly, and you're handling custom click events correctly by binding using custom directives.
For instance, if your client says, "hey, now let's make it call the server and make bread, and then popup a modal." You will be able to easily just go to the service itself without having to add or change any of the HTML, and/or controller method code. If you had just the one line on the controller, you'd eventually need to use a service, for extending the functionality to the heavier lifting the client is asking for.
Also, if you need another 'Delete' button elsewhere, you now have a directive attribute ('ng-remove-birthday') you can easily assign to any element on the page. This now makes it modular and reusable. This will come in handy when dealing with the HEAVY web components paradigm of Angular 2.0. There IS no controller in 2.0. :)
Happy Developing!!!
Here is another answer. I hope it will help.
<a class="btn" ng-click="delete(item)">Delete</a>
$scope.delete(item){
var index = this.list.indexOf(item);
this.list.splice(index, 1);
}
array.splice(start)
array.splice(start, deleteCount)
array.splice(start, deleteCount, item1, item2, ...)
Full source is here
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
if you have ID or any specific field in your item, you can use filter(). its act like Where().
<a class="btn" ng-click="remove(item)">Delete</a>
in controller:
$scope.remove = function(item) {
$scope.bdays = $scope.bdays.filter(function (element) {
return element.ID!=item.ID
});
}
Pass the id that you want to remove from the array to the given function
from the controller( Function can be in the same controller but prefer
to keep it in a service)
function removeInfo(id) {
let item = bdays.filter(function(item) {
return bdays.id=== id;
})[0];
let index = bdays.indexOf(item);
data.device.splice(indexOfTabDetails, 1);
}
An inline simple way is just add bdays.splice($index, 1) in your delete button.
<ul ng-repeat="bday in bdays">
<li>
<span ng-hide="editing" ng-click="editing = true">{{bday.name}} | {{bday.date}}</span>
<form ng-show="editing" ng-submit="editing = false">
<label>Name:</label>
<input type="text" ng-model="bday.name" placeholder="Name" ng-required/>
<label>Date:</label>
<input type="date" ng-model="bday.date" placeholder="Date" ng-required/>
<br/>
<button class="btn" type="submit">Save</button>
<a class="btn" ng-click="bdays.splice($index, 1)">Delete</a>
</form>
</li>
</ul>

foreach over object array not working properly

I'm using Charts,js by devex (find the link to the documentation by clicking here). I'm also using the Laravel framework. I need to generate some JQuery on the server side to output the graphs I want. I am passing $json_micromarket_participants which is an array of objects (rows from database query) that are json_encoded in my controller. Each object has a Home_name and Average_Occupancy property.
For some reason my foreach loop doesn't work, i.e. I get the following error:
Invalid argument supplied for foreach()
My question is twofold:
1. Why doesn't it work?
2. Would this code work anyway to generate name
and value pairs in jquery?
Code:
#section('content')
<script type="text/javascript">
var chartDataSource = {{ $json_micromarket_participants }};
$(function () {
$("#chartContainer").dxChart({dataSource: chartDataSource,
commonSeriesSettings:{argumentField: 'Home_name'},
series: [
#foreach($json_micromarket_participants as $micromarket_participant)
{
name: '{{$micromarket_participant->Home_name}}',
valueField: '{{$micromarket_participant->Average_Occupancy}}'
},
#endforeach
]
});
})
</script>
<div id="chartContainer" style="max-width:700px; height:300px;"></div>
#stop
In the controller, here's how $json_micromarket_participants is set. It's all fine on that side I think...
$micromarket_participants = DB::table('homes')
-> select(array('*', DB::raw('SQRT(POW('.$Eastings.' - `Eastings`,2) + POW('.$Northings.' - `Northings`,2)) AS distance')))
-> having('distance', '<', $micromarket_size)
-> get();
$json_micromarket_participants = json_encode($micromarket_participants);
It is not working because you have encoded $micromarket_participants into json, making it a string, not an array.
I think $micromarket_participants is the array of objects in this case, so you should just use this in your view:
#foreach($micromarket_participants as $micromarket_participant)
I think your issue is that you are calling json_encode on the $micromarket_participants object, which I don't think that will return what you want. Instead, try just calling the toJson method on the returned collection:
$json_micromarket_participants = $micromarket_participants->toJson();

What is the simplest way to load language keys to a view in Codeigniter?

I'm using codeigniter and I'm building a multilingual site, so I use Language class like this:
$this->lang->load('index', 'english');
Then, in the controller, to load all the data into my view I do this:
$data["var1"] = $this->lang->line('language_key1');
$data["var2"] = $this->lang->line('language_key2');
$data["var3"] = $this->lang->line('language_key3');
$data["var4"] = $this->lang->line('language_key4');
$data["var5"] = $this->lang->line('language_key5');
...
$this->load->view('index', $data);
The problem is that in some controllers I have to load more than 100 language keys, and I wonder if there is a simpler way to do this.
There is a simple way to do this instead of language class you can use language helper.
Here is you can see the documentation
In you view you can use this
<p><?php echo lang('language_key1')?></p>
Also if you want to use language class you can use it like this
$data['language'] = $this->lang->load('index', 'english',true);
Passing third parameter as true will return the array of language items. Then in the view you can use like this
echo $language['language_key1'];
CI has lang() function in system/language_helper.php. And it uses directly in your template.
<?php lang('s_no') ?>
OR
<input type="submit" class="bigButton" value="<?php lang('lang_continue') ?>" />
More http://ellislab.com/codeigniter/user-guide/helpers/language_helper.html

How to add extra parameter in zend paging

How i can add extra parameter in the zend paging.I have to provide filter functionality in the listing user. so i want to send search keywords with page numbers.
Paging code
$page = $this->_getParam('page', 1);
$paginator = Zend_Paginator::factory($data);
$paginator->setItemCountPerPage(2);//PAGING_RESULT_PER_PAGE
$paginator->setCurrentPageNumber($page);
$paginator->setPageRange(PAGING_PAGES_RANGE_PER_PAGE);
$this->view->users = $paginator;
I want to add search data onchange event to the paging .
This paging is working using ajax now what i want to it should be changed as per the filter data. I am not able to perform this....can you please provlde me any suggestion please
You can change the code from the javascript.
<script>
$(document).ready(function(){
$('.paginationControl a').click(function(){
if($('#keyword').val() != '')
{
var href = $(this).attr('href')+'/keyword/'+$('#keyword').val();
$(this).attr('href', href);
}
});
});
</script>
<input type="text" name="keyword" value="" id="keyword"/>
<div class="paginationControl">
2
3
4
5
</div>
I'm not quite sure what you mean with "extra parameter in the zend paging" ... are you trying to pass a GET-Parameter to an controller which has an paginator? What is inside $data? How does your search parameter and your route look like? You might try the following inside your bootstrap.php (if passing a get var is what you're struggling with):
protected function _initConstants()
{
[...]
defined('QSA_SEARCH') || define('QSA_SEARCH', 'q');
[...]
}
And inside your controller you can access it via:
[...]
$search = $this->getRequest()->getParam(QSA_SEARCH);
[...]
Passing a search string via get request:
http://domain.com/<controller>/<pagenum>?q=<searchstring>
e.g.:
http://domain.com/users/2?q=foo
EDIT:
Or are you having problems passing the search string towards Zend_Paginator::factory?

Categories